Privacy Policy
Last updated: 2026-11-03. Written against what the code does, not what policies usually say.
1. Who we are
ChartOmodo ("we", "us") is a chart builder for Notion, built and operated by PT Gagah Sukses Perkasa (ASAK Digital Agency), a company in Indonesia. It reads a Notion database you choose and draws a chart you can embed back into a Notion page.
This policy describes how we handle personal data when you use https://chartomodo.com. It is written against what the software actually does: if you find a statement here that the product does not match, tell us and we will correct the policy or the code.
Contact for anything in this policy, including data requests: support@chartomodo.com.
2. What we store
Account: your email address, a hashed password (none if you only ever sign in with Google or Notion), an optional display name and avatar URL (taken from your Google or Notion profile when you sign in with one), whether your email is verified, and the dates the record was created and last changed. If you sign in with Google or Notion we also keep that provider's account ID, so we recognise you next time. We keep no Google sign-in token. The sign-in record for either provider holds no token; signing in with Notion also connects your Notion workspace, and that token is kept as described under Data source credentials below. We also keep two email settings, connector alerts and product emails from the team (both on by default), and the date we sent, or tried to send, the one email that asks what you wanted to chart (section 8).
Sign-up source: the link or site that first brought you here, if you pressed Accept on the cookie banner before signing up. That is the utm_source, utm_medium and utm_campaign tags and the ref code of the link you followed, the domain of the site that linked to us (never the full address) and the first page you opened (never its query string). We record it once, within 24 hours of sign-up, and never change it. If you declined, never answered, or typed our address yourself, these fields stay empty. We use them only to count which links and directories bring people who sign up and stay. They are part of your account record, so they appear in your export (section 9) and go when the account goes (section 10). Section 11 describes how they get from your browser to us.
Sessions: a session token, its expiry, and the IP address and browser user-agent of the device that signed in. We keep these to detect and investigate suspicious sign-ins. Every session on the account is destroyed when the password is reset.
Data source credentials: your Notion access token (and refresh token, if Notion issues one), plus the Notion workspace ID and bot ID of the connection. If you connect a PostgreSQL or MySQL database, we also store what you enter to reach it: host, port, database name, user name, password, SSL mode and any CA certificate, kept together as one encrypted value. Only the host, port and database name are also kept readable, to label the connector on screen. If you connect Google Analytics 4 or Search Console, we store the email address of the Google account you connected and the refresh token Google issues for the one read-only permission you granted, encrypted together as one value; the email is also kept readable, to label the connector on screen (section 4). The old Google Sheets flow that sat unfinished behind an environment flag was removed outright: its code, its OAuth callback and the three database columns that could have held Google tokens are gone. Adding a Google Sheets tab by link (once we switch it on) stores no Google token and no password: we keep the spreadsheet's ID and the tab's ID, encrypted, with the dataset. Signing in with Google is separate from the connectors and stores no Google token (section 7): a connector is a grant of its own, made on Google's consent screen when you add it. Every token and database credential we store is encrypted before it is written to the database (see section 5).
CSV uploads: available, and stored in full. When you upload a CSV we parse it and keep the parsed rows in our database: there is no upstream to re-fetch them from, so this is the stored copy rather than a cache. An upload is capped at 5 MB and 50,000 rows. Deleting the connection or the account deletes the rows with it.
Google reports: when you add a report from Google Analytics 4 or Search Console, we copy the aggregated report you pick (for example sessions per day, or clicks per search query), up to 50,000 rows, into our database, and replace that copy on the schedule you choose. Charts and embeds read the copy. Deleting the dataset or the account deletes it; deleting the connector deletes the token at once, and its datasets keep their last copy as uploaded files until you delete them.
Google Sheets tabs: when you add a tab from a spreadsheet you published to the web or shared with anyone who has the link (once we switch it on), we copy its rows, up to 50,000 rows and 10 MB, into our database, and replace that copy on the schedule you choose. Charts and embeds read the copy. Anyone who holds such a link can read the sheet, so we treat the link as a secret: the spreadsheet and tab IDs are stored encrypted and kept out of logs. Deleting the dataset or the account deletes the copy and the IDs; deleting the connector deletes the IDs at once, and its datasets keep their last copy as uploaded files until you delete them.
Database tables: when you add a table from a connected database, we copy the columns you pick, up to 50,000 rows and 10 MB, into our database, and replace that copy on the schedule you choose. Charts and embeds read the copy, never your database. The copy lasts as long as the dataset: deleting the dataset or the account deletes it. Deleting the connector deletes its credentials at once; its datasets keep their last copy as uploaded files until you delete them.
Stripe (Beta): if you connect Stripe, we store the restricted API key you paste and whether it reads test or live data, encrypted together as one value (section 5); on screen the connector shows only whether the key reads Live data or Test data. Each sync stores, per month and currency, your MRR, ARR, number of paying customers and MRR movements, and, to work out those movements, one MRR amount per Stripe customer ID (cus_…) for each month since you connected, kept for at most 37 months. We store no customer name, email address or payment details. Deleting the connector deletes the key and the per-customer amounts at once; its dataset keeps the monthly totals as an uploaded file until you delete it.
Charts and dashboards: the chart name, type, rendering engine, axis and styling configuration, the ID of the Notion database it points at, the ID of the Notion workspace it reads from, whether it is public, its embed token, and a view counter. Dashboards additionally store their layout and share token.
Organizations: if you invite people into your organization, or join someone else's, every member of that organization sees the other members' names and email addresses, the names of the connected Notion workspaces, databases and tables, the name, host or Google account label of every database or Google connector, every pushed dataset, the name and prefix of every API token (never the secret), and every chart and dashboard in it. We record who created each chart, dashboard, data source and API token, and who authorized each Notion connection. When an owner invites someone, we store the invited email address, who sent the invitation and its status; a pending invitation expires after 7 days, and the record is deleted with the organization. We send one invitation email to that address and nothing else. The owner can remove a member at any time, and a member can leave; either way access ends at once, and what they made stays in the organization, except the API tokens they created, which are revoked. Inviting people is part of Teams, which is available on the Business plan once we switch it on.
Billing: a customer ID and a subscription record from Creem, our payment processor (tier, billing interval, status, period dates, cancellation flags), plus the raw webhook payloads Creem sends us, which we keep so billing events are replay-safe and auditable. Those payloads are Creem's own event objects, so they can contain your email address, your name, your billing address and the last four digits of your card. Each stored payload now carries the customer ID it belongs to, written by the code that receives the event, so deleting your account deletes them with it, and any that outlive an account are deleted 90 days after we receive them. See section 10. We never see or store your full card number; that stays with Creem. If you pay in Rupiah, we also keep the invoice (plan, amount, dates, status and the name and email printed on it) and TriPay's payment status messages, which carry your name and email. Deleting your account deletes those messages and blanks the name and email on the invoice; the amounts and dates stay for bookkeeping.
Audit log: one row per security-relevant action (password reset, password change, account deletion, forced logout, plan override, and an admin starting or stopping impersonation). The same log also records dashboard lifecycle events (created, deleted, shared, unshared, share token rotated), organization events (invitation sent, accepted or cancelled, member removed or left, a former member's API tokens revoked) and every billing event we receive: subscription cancelled, trial ending, invoice paid, payment failed, invoice upcoming, customer created, charge refunded, subscription expired, webhook errors, and the provider's own event-type string alongside them. Notion telling us a database changed is logged too.
Each audit row holds an actor, an action and a timestamp. The actor is not always a user ID: on a webhook row it is the billing customer ID or a system identifier such as "creem" or "notion-webhook". An IP address is recorded only on the admin actions.
Error reports: see section 6.
3. What we do not store
Notion row content. Row values are fetched on demand and held in a short-lived server cache (see section 4). They are never written to our database.
Notion content blocks. We read your database's schema and its rows through the Notion API and nothing else: no page bodies, no paragraphs, no images, no comments, no other database you have not connected.
Card numbers, CVCs or bank details. Checkout and the billing portal are hosted by our payment processor; that data never reaches our servers.
Visit analytics on the public pages. Our public pages (the home page, pricing, features, product, compare, docs, roadmap, support and the legal pages) can load Google Analytics 4 to count visits: which page, which referrer or campaign, rough location, device and browser type, set against a pseudonymous cookie ID. It loads only after you press Accept on the cookie banner; until then, or if you decline, it does not load at all. It never loads inside the app, the admin area, the sign-in pages or your embeds, and it is switched off the moment you move from a public page into one of them, so nothing about your account, your charts or your Notion data reaches it. We run no advertising pixel, we have not turned on Google signals or ad personalisation, and we build no profile of you. The same Accept also allows one thing in the other direction: if you go on to sign up, the link or site that first brought you here is stored with your account (section 2). Google never receives it.
Product analytics. What we do measure inside the app is a small set of first-party ProductEvent events (sign-up, connect, connector activated, connector table added, template used, first chart, chart builder opened, no shared database, which way in you picked on the connect page (Notion, sample data or a template), first embed view, first view from inside Notion, paywall shown, badge click-through) stored as counts with a user id and timestamp (no cookie, no IP address, no user-agent), so we can see where the funnel leaks and nothing else.
Performance telemetry. Sentry samples 10% of performance transactions, and that sample includes client-side route changes, so a fraction of the moves you make between pages is recorded as timing data. See section 6.
Public embed views. Each public chart keeps a view counter. To avoid counting the same viewer twice within an hour, we store a key of the form view:<chart id>:<first 16 hex characters of a SHA-256 hash of the viewer's IP address> in Upstash Redis for one hour. That is a truncated, hashed IP address of everyone who loads a public embed, held for an hour and then gone. It is not reversible into an address and it is not linked to an account.
We do not sell personal data, we do not share it with anyone for marketing, and we do not use your Notion data (or anything else you give us) to train machine-learning models.
4. Notion, Google and Stripe data specifically
Access is granted by you through Notion's OAuth flow, and it covers only the pages and databases you explicitly share with the ChartOmodo integration during that flow. Notion, not us, decides what that grant reaches; we cannot widen it from our side.
We call exactly three Notion data endpoints, all of them read-only: search, to list the databases you shared with us so you can pick one; database retrieve, to read that database's property names and types; and database query, to read the row values needed to draw the chart. On top of those we use Notion's OAuth endpoints when you connect: we redirect you to its authorize page and exchange the result at its token endpoint. We make no write calls anywhere: ChartOmodo cannot create, edit or delete anything in your workspace.
Row values are held in a short-lived cache on our server, never our database, so a chart or embed loads without hitting Notion on every view. It is the framework's data cache, which on a self-hosted server like ours is written to the server's filesystem rather than kept in memory. Each entry expires on its own, and how long it lives depends on your plan: Free 300 seconds, Starter 60 seconds, Pro 60 seconds, Business 30 seconds, Enterprise 30 seconds.
The cache also refreshes ahead of that timer when Notion tells us via webhook that the database changed. We verify the webhook's signature and use only the database ID in it to invalidate the cache; we do not store the payload.
To revoke our access, remove the ChartOmodo integration from your Notion workspace (Notion → Settings → Connections → ChartOmodo → Remove access). That invalidates the token at Notion's end, which is what actually stops us reading. Deleting the connection on the ChartOmodo Connect page (/connect) deletes our stored copy of that connection's token and also asks Notion to revoke it. That request can fail (a network error, or Notion refusing it), and we skip it when another ChartOmodo account uses the same Notion integration install, so removing access in Notion is still the step that is certain to end it.
After revocation, rows already in the cache stay readable until their timer expires (at most five minutes, on the Free tier) and are not refreshed after that, because the next fetch fails against a revoked token.
Your Notion data is never sold, never shared with another customer, and never used to train a model. It is read to draw your chart and for nothing else.
Google Analytics 4 and Search Console are optional connectors on the plans that include connectors. You grant access on Google's own consent screen, one read-only permission per connector: analytics.readonly for Google Analytics 4 and webmasters.readonly for Search Console, plus your account's email address so you can tell connectors apart. We cannot widen that grant from our side.
We call these Google endpoints, all read-only: the Analytics Admin API's account summaries and the Search Console sites list, so you can pick a property or site; the Analytics Data API's runReport and the Search Console searchAnalytics query, to read the report you picked; and Google's OAuth token and revoke endpoints. The reports we request are aggregates, with no individual visitor records.
The refresh token is encrypted with the same AES-256-GCM key as every other credential (section 5). Our server uses it only to ask Google for a short-lived access token at the moment of a sync or a listing, or to ask Google to revoke it. Access tokens are never stored.
ChartOmodo's use and transfer of information received from Google APIs adheres to the Google API Services User Data Policy, including the Limited Use requirements. Read the policy.
In practice: data from Google is used only to show you the charts you build from it. It is not sold, not used for advertising, not used to train any model, and not transferred to anyone except the sub-processors that run this service (section 7). No person reads it unless you ask us to (for support), it is needed for security, or the law requires it.
To end our access, delete the connector: we delete the stored token and ask Google to revoke the grant, unless another ChartOmodo connector still uses the same Google account. Deleting your account makes the same request for each Google connector on it. That request can fail, so the step that is certain to end it is removing ChartOmodo in your Google Account: open myaccount.google.com/linkedapps, choose Access to your Google Account, pick ChartOmodo, then Remove access. A revoke ends ChartOmodo's whole grant for that Google account, so if you also sign in with Google, Google may ask for your consent again the next time you press Continue with Google.
Stripe is an optional connector on the plans that include connectors. It reads your Stripe account with a restricted key you create in your Stripe Dashboard, with Read access to Customers, Subscriptions, Prices, Products and Coupons and nothing else; we refuse secret keys (sk_), which can refund and change data. We only read subscriptions, their items, prices, products, coupons and customers, and from them keep only what section 2 lists. Deleting the connector does not revoke the key at Stripe: to end our access, delete the connector, then roll or delete the restricted key in your Stripe Dashboard (Developers → API keys). Replace a connector's key only with a key from the same Stripe account; a key from another account mixes that account's numbers into the connector's history, so connect another account as a new connector.
5. How your tokens are protected
Notion tokens are encrypted with AES-256-GCM (an authenticated cipher, so a tampered ciphertext fails to decrypt rather than decrypting to something wrong), using a 256-bit key held in the server environment and never in the database or the source tree. Each value gets a fresh random 96-bit IV.
The key lives only in the deployment environment. Anyone reading a database dump gets ciphertext and nothing else.
Tokens are decrypted in memory only for the duration of a Notion API call, or, for a Google connector's refresh token, only while we ask Google for an access token or ask it to revoke the grant. They are never sent to the browser, never written to logs, and are excluded from your data export.
Database credentials get the same cipher and key. Our server decrypts them in memory only to test the connection, list tables and columns, or run a sync. They are never sent to the browser (the edit form shows the password as dots) and excluded from your data export. The password and any CA certificate are never written to our logs or the audit log. A connection error we log can include your database host and user name. The audit log records only that an action happened (for example that a connector was created or deleted) and, for a failed test or sync, a short error code. It holds no credentials and no row values. We refuse superuser accounts, and every query runs inside a read-only transaction. Deleting a connector deletes its credentials permanently.
When you delete a connection, that connection's stored tokens are deleted with it. Deleting a Notion workspace disconnects that workspace only. Its charts stay in your account but stop showing data, embeds included, until you reconnect the same workspace. Any other Notion workspace you have connected is unaffected.
When you delete your account, every token in your own organization goes with it, and we ask Notion to revoke each Notion token and Google to revoke each Google connector's grant as well. Notion connections, Google connectors and database connectors you added in someone else's organization stay with that organization, with their tokens and credentials, and are not revoked. Either request can fail or be skipped, as described in section 4, so remove access in Notion or your Google Account too if you want to be certain.
6. Error monitoring
Runtime errors and a 10% sample of performance transactions (including client-side route changes) are sent to Sentry so crashes get fixed. Sentry's "send default PII" option is switched off, so IP addresses and request bodies are not attached to events.
Every outbound event first passes through a scrubber that redacts embed tokens, share tokens and password-reset tokens from URLs, error messages, breadcrumbs and span data, because an embed URL is itself the credential for a private chart.
Error events can still incidentally contain a user ID or a database ID inside a stack trace or message. They are not a deliberate collection channel and are retained under Sentry's own retention schedule.
7. Sub-processors
Contabo: the virtual private server that runs the application, in a data centre in Contabo's European Union region (inside the EEA). PostgreSQL runs natively on that same server (not in a container) and is administered by us, not by a managed database service, so nobody at Contabo touches the database itself. Holds everything in section 2.
Creem: checkout, subscriptions, invoices and tax. Receives your email address and your card details directly at its own hosted checkout; what comes back to us is a customer ID, a subscription ID and a status.
TriPay (PT Trijaya Digital Grup, Indonesia): Rupiah payments by QRIS and bank virtual account. Receives your name, your email address and the amount; you pay on TriPay's own hosted page, and the payment itself runs through TriPay's bank and QRIS partners and your own bank or e-wallet. What comes back to us is a payment reference, the channel and a status.
Resend, for email: address verification and password-reset links, Teams invitations, token-revocation notices to organization owners, connector sync-failure alerts (on by default; turn them off under Settings), one email a few days after your first chart that asks what you wanted to chart (sent once; turn product emails off under Settings), and, if you pay in Rupiah, invoice and receipt emails. Receives your email address and the message.
Sentry: error and performance monitoring, as described in section 6.
Upstash Redis: rate limiting on sign-up, sign-in, change-password, password-reset requests and everything under /embed/, plus the one-hour embed view-dedupe key described in section 3. Receives the requesting IP address, as part of a counter key for the limits and hashed and truncated for the embed counter; it holds no account data.
Google Analytics 4 (Google LLC): visit counts on the public pages only, as described in section 3. Receives the page address, referrer, a pseudonymous cookie ID, and your IP address, which Google uses to derive a rough location and does not store. It never sees your account, your charts or your Notion data.
Google Sign-In (Google LLC): only if you press Continue with Google. Google confirms who you are and sends us your name, email address, profile photo URL and Google account ID; we ask for nothing beyond the openid, email and profile scopes. Signing in keeps no Google token, so sign-in alone lets ChartOmodo read nothing else in your Google account; a Google Analytics 4 or Search Console connector is a separate grant you make when you add one (section 4).
Notion, and Google Analytics 4 or Search Console if you connect them: sources you connect, not sub-processors (section 4). The two Google entries above are separate from those connectors: the visit counts on the public pages never receive connector data, and signing in with Google gives no access to your reports.
That is the complete list, and there is no AI provider on it. Each entry is set out in full (what it receives and why) at Sub-processors. We add none silently: a new sub-processor means an update to this section under the notice rules in section 13. Every provider except TriPay is outside Indonesia, so for users in Indonesia using the service means a transfer abroad; section 10 of that page says how we handle it.
8. Why we are allowed to hold it (legal bases)
Performance of a contract: your account, your charts, your connections, your subscription. Without these there is no service to deliver.
Legitimate interest: session IP and user-agent, rate-limit counters, the audit log and error monitoring, all of it for security, abuse prevention and keeping the service working. We balanced this against your interests and kept the data minimal and short-lived. Legitimate interest also covers occasional product emails from the team: a question, or help finishing setup. They sell nothing, replies reach the team at support@chartomodo.com, and you can turn product emails off under Settings. One of them is a single question a few days after your first chart, to learn what you came to chart; we keep the date we sent it so it goes out once.
Legal obligation: billing and tax records.
Consent: visit analytics on the public pages (section 3) and the sign-up source (section 2) run only if you press Accept on the cookie banner, and you can withdraw that at any time as described in section 11. Withdrawing stops both from then on; a sign-up source already on your account stays until you email us to remove it (section 14) or delete the account (section 10). Nothing else depends on consent, and we send no marketing email: product emails ask a question or help you finish setup, and sell nothing.
These are the GDPR's terms. Indonesia's Personal Data Protection Law (UU 27/2022, Article 20) recognises the same bases (performance of a contract, a legal obligation, legitimate interest and consent), and we rely on them in the same way for users in Indonesia.
9. Your rights
We apply these rights to everyone who asks, wherever you live. ChartOmodo is operated from Indonesia; where the GDPR, UK GDPR or CCPA/CPRA apply to you, they apply on top of what is written here and we do not ask you to prove which one you are covered by.
Access and portability: Settings → Export downloads a JSON file with your account record, every connection (its type, its workspace ID and its metadata, never the tokens), every database or Google connector (its name, type, host or account label and status, never the credentials or tokens), the rows of any CSV or database table stored against a connection, every chart, every dashboard, your subscription record and any linked sign-in accounts. It holds the contents of your own organization and the list of organizations you belong to; the contents of someone else's organization are not included.
Three things are left out of that file on purpose. Data source tokens, your password hash and your session tokens are never exported. Embed and share tokens appear as a yes-or-no flag rather than the token itself, because an embed token is the credential that opens a private chart: an export file that gets forwarded or backed up is not a safe place to carry live credentials. You can always read a share token from the chart or dashboard itself.
Correction: email us what is wrong and we will fix it. The settings screen lets you change only your password and your email settings; there is no self-service editor for your name or email address yet.
Deletion: Settings → Delete account. See section 10 for exactly what that removes.
Objection and restriction: email support@chartomodo.com and say what you object to. The practical consequence of objecting to security logging or error monitoring is usually that the account cannot be operated, so we will tell you honestly what a restriction would break before acting on it.
Indonesia's Personal Data Protection Law (UU 27/2022) gives the same rights, plus the right to claim compensation for unlawful processing. It also sets deadlines: we give access, correct data, and stop or restrict processing within 3 x 24 hours of receiving the request, as that law requires. We meet those deadlines for everyone, wherever you live.
Other requests we answer within 30 days, and we charge nothing for any of them. We do not discriminate against anyone for exercising a right: there is no "pay more if you opt out" tier.
If a breach of security exposes your personal data, we tell you in writing within 3 x 24 hours of becoming aware of it: what was exposed, when and how, and what we are doing about it. Where the law requires it, we notify the data protection authority in the same window.
If we get it wrong, you may complain to your local data protection authority (in Indonesia, the authority set up under UU 27/2022). We would rather you emailed us first.
10. Retention and deletion
While your account is open, we keep the data in section 2 for as long as you keep the account.
Deleting your account is immediate and irreversible. Settings → Delete account asks you to type your email address to confirm, then deletes the user record and, by database cascade, your sessions, your password hash, every connection and the tokens and any CSV or database rows inside them, every database or Google connector with its encrypted credentials or token, every chart, every dashboard, every subscription record, and any pending password-reset token. There is no grace period and no undo, so if you want your charts, export first.
Three things survive. Security audit-log rows are kept deliberately: they record that a deletion happened, and an audit log you can erase by deleting the account is not an audit log. They contain a user ID and an action, not your email or your content. Card payment and tax records are held by our payment processor under its own retention schedule, as tax law requires. Rupiah invoices paid through TriPay are kept in our own database instead, for bookkeeping, with the buyer's name and email blanked: the invoice number, plan, amount, dates and payment reference stay for the ten years Indonesian tax law requires business records to be kept.
The billing webhook records described in section 2 used to be a third survivor. They are not any more: every one we receive is now filed with the customer ID it belongs to, so account deletion reaches it, and a scheduled job deletes any row older than 90 days whether or not an account is attached. The manual-removal offer we published while that was untrue no longer applies, because there is nothing left to remove by hand.
Organizations and deletion: deleting your account deletes your own organization and everything in it, including what its members made. What you made in someone else's organization is a different case: it stays there, no longer linked to your account (a Google connector still shows the Google account it reads from). The one exception is the API tokens you created there, which are revoked.
Cached Notion rows are not deleted so much as abandoned: they expire on their own timer within five minutes at most, and nothing refreshes them once the account is gone.
Database backups are taken by us, on the same Contabo server in the EU, and are deleted 30 days after they are written. The schedule is ours rather than a provider's, and the 30-day window is not a policy we keep to by hand: the backup script deletes every dump older than that on each run. So a deleted record can persist in a backup for up to 30 days after deletion, and no longer. Backups are encrypted and are restored only in a disaster, never to recover an individual deleted account.
11. Cookies and local storage
Session cookie: set by our authentication library when you sign in. HttpOnly, so scripts cannot read it. It is what keeps you signed in; without it the app cannot work.
notion_oauth_state: set for the duration of the Notion connection flow to prevent cross-site request forgery. HttpOnly, SameSite=Lax, secure in production, one-hour lifetime, deleted as soon as the flow completes.
gc_oauth: set for the duration of the Google Analytics 4 or Search Console connection flow to prevent cross-site request forgery; holds that flow's state, encrypted. HttpOnly, SameSite=Lax, secure in production, sent only to /api/connectors/google, ten-minute lifetime, deleted as soon as the flow completes.
currency: set only if you use the USD/IDR switch on the home or pricing page, to remember which currency you picked. It holds the value usd or idr and nothing else, lasts one year, and is set by a script in your browser, so it is not HttpOnly.
_ga and _ga_J1Y73HCF6M: set by Google Analytics on the public pages only (the home page, pricing, features, product, compare, docs, roadmap, support and the legal pages). Set only after you press Accept on the cookie banner. They hold a random ID so repeat visits are counted once, and last up to two years. They are never set inside the app or on an embed.
signup-attribution: not a cookie but a local storage entry, written on the public pages only after you press Accept, and only if you arrived through a tagged link or from another site. It holds the details listed under Sign-up source in section 2, plus the time it was written. The first one wins: a later tagged link or referring site does not replace it. The next time you open the app after signing up, your browser sends it to us and then deletes it (if the request does not get through, it tries again on your next visit). We keep it only if it was written before you created the account and the account is under 24 hours old; otherwise we discard it. An entry is ignored once it is 30 days old.
Those are the only cookies our code and the scripts we load set. Four are ours: three strictly necessary, one remembering a choice you made. The two Google Analytics cookies are the only analytics cookies, and we set no advertising or cross-site tracking cookie. Declining on the banner keeps them from being set. To change your mind later, use Cookie settings at the foot of any public page: withdrawing deletes the two cookies and the signup-attribution entry and stops Google Analytics straight away. Your choice is remembered in your browser's local storage. The site works the same either way.
We stop short of saying no other cookie can exist. The authentication library we use mounts its own set of endpoints, and it could set an internal cookie of its own that we do not control. The four first-party cookies named above are the ones our code sets, and none of them tracks you.
Your theme choice, sidebar state and builder panel layout are kept in your browser's local storage, not in a cookie. They never leave your device and are never sent to us.
12. Age
ChartOmodo is not intended for anyone under 16, and we do not knowingly collect data from children. If you believe a child has created an account, email support@chartomodo.com and we will delete it.
13. Changes to this policy
The last-updated date at the top of this page changes whenever this policy does.
For a material change (a new sub-processor, a new category of data, a new purpose), we will email you and show an in-app notice at least 30 days before it takes effect.
14. Contact
Email support@chartomodo.com for anything: a privacy question, a data request, an objection, or a correction to this page. The ChartOmodo team reads that inbox and answers within two business days.
A suspected vulnerability goes to the same address: please give us a reasonable window to fix it before disclosing publicly. How we handle a report, and how the service is secured, is set out at Security.