Set up website tracking

Chartsy's tracking script connects the traffic arriving at your site to the customers who end up paying - so you can see which channel brought each signup, which ones convert, and which ones produce customers who stay.

Three steps are required. Two more sections apply only if your site spans several domains or shows a cookie banner. Platform-specific instructions - Webflow, Squarespace, Wix, WordPress, GTM, Framer - are in Install by platform.

What you need first#

  1. A Chartsy account with your site added under Settings → Domains.
  2. Access to your site's HTML - a shared layout file, your CMS's header-injection setting, or Google Tag Manager.
  3. A connected payment provider (Stripe or Paddle) if you want revenue by source. You can install tracking first and connect billing later.

Tracking is disabled on localhost by default, so pointing a real key at your dev environment will not burn your monthly event allowance.

1. Add the tracking script (required)#

Copy your snippet from Settings → Domains, or from the setup block on the Launches page. It carries your own site key:

<script async src="https://chartsy.fra1.digitaloceanspaces.com/production/static/track.js"
        data-key="ch_pk_your_key_here"
        data-api="https://dashboard.chartsy.app/api/attribution"></script>

It must render in <head> on every page. Where to put it:

Your setupWhere it goes
Framework with a shared root layoutapp/layout.tsx, layouts/default.vue, +layout.svelte or your base template - once
WordPress, Webflow, Squarespace, Wix, FramerThe site-wide custom code / header injection setting
Google Tag Manager already installedA Custom HTML tag firing on All Pages
Static multi-page HTMLBefore </head> on every page

Add it once per page load. Two copies double-count everything.

Script attributes

AttributeRequiredWhat it does
data-keyYesYour site's public key. Safe to expose - it is in your page source.
data-apiYesWhere events are sent. Use the value from your snippet.
data-allow-localhostNoSet to "true" to track on localhost while developing. Off by default.
data-consentNoRarely needed. Duplicates the "Ask everyone first" cookie mode - use the setting instead.

Check it worked

Load your site, then open Settings → Domains and click View setup checklist on the site's row. "Add tracking snippet" flips to done as soon as the first visit lands. That item is inferred from real traffic, so it is the only confirmation the snippet is actually firing rather than just pasted somewhere.

2. Tell Chartsy who signed up (required)#

Visits alone cannot be tied to revenue. Chartsy needs the email address at the moment someone creates an account. Pick whichever route matches your signup flow.

A real form

Add data-chartsy-signup to the <form>. The email field is picked up on submit - no JavaScript to write.

<form action="/signup" method="post" data-chartsy-signup>
  <input type="email" name="email" required>
  <button type="submit">Create account</button>
</form>

JavaScript or single-page apps

Call identify yourself, right after the signup succeeds:

window.chartsy.identify({ email: 'person@example.com' });

OAuth and social login

"Continue with Google" redirects the browser away and back, so there is no page left running to fire identify(). Handle it from your backend, right after the callback creates the user. The cookies the script already wrote survive the round trip:

// Node / Express - from your OAuth callback handler
const first = JSON.parse(decodeURIComponent(req.cookies.chartsy_attrib || '{}'));
const last  = JSON.parse(decodeURIComponent(req.cookies.chartsy_attrib_last || '{}')) || first;

await fetch('https://dashboard.chartsy.app/api/attribution/identify/', {
  method: 'POST',
  headers: {
    'Content-Type': 'text/plain',
    'Authorization': `Bearer ${process.env.CHARTSY_SECRET_KEY}`,
  },
  body: JSON.stringify({
    email: user.email,
    attribution_first: first,
    attribution_last: last,
    visitor_id: req.cookies.chartsy_visitor_id || '',
  }),
});

Keep the secret key server-side

Environment variable or secrets manager, never committed and never sent to the browser. Unlike the public key, it authenticates your backend.

Send the request even when the cookies are missing. A signup with no known source still counts; one that never arrives is invisible.

3. Connect revenue to sources (required for revenue)#

Chartsy matches signups to paying customers by email. That breaks when someone pays with a different address than they signed up with - a personal signup and a company billing address, for example.

Attaching the visitor id at checkout fixes it permanently:

// Stripe Checkout Session or PaymentIntent
metadata: { chartsy_visitor_id: req.cookies.chartsy_visitor_id }

// Paddle transaction or checkout
custom_data: { chartsy_visitor_id: req.cookies.chartsy_visitor_id }

Revenue and churn then follow the visitor rather than the address, and keep working when the two diverge.

If your site spans more than one domain#

Install the same snippet, with the same key, on every domain - and register each of them under Settings → Domains. Both halves matter: the script has to be present to measure anything, and the domain has to be registered for Chartsy to recognise it as yours rather than as an outside referral.

Subdomains - example.com and app.example.com - need nothing else. Registering the root covers every subdomain, and the two share a cookie automatically.

Separate root domains - example.com and exampleapp.io - cannot share a cookie at all; browsers keep them in separate jars. Chartsy handles the handover: when a visitor clicks from one of your registered domains to another, their identifier travels on the link as a _chid parameter, and it is removed from the address bar as soon as it is read. A signup on the second domain is attributed to the campaign that landed on the first, and the whole crossing counts as one visit rather than two.

It follows real links

The handover attaches to <a href> clicks. A button that navigates with window.location = … or a router push will not carry it; framework link components such as Next.js <Link> render real anchors and work fine. Pages viewed before crossing stay with the domain they were viewed on - attribution crosses, the page-by-page journey does not.

Cookie modes#

Set per site under Settings → Domains → Cookies & consent. Every mode measures every visitor; what cookies add is cross-session identity - who came back, and what first brought them.

ModeBehaviourCost
Cookies where permitted (default)Visitors whose country allows first-party analytics cookies get full 90-day attribution. EEA and UK visitors are measured cookielessly, automatically.None. Best accuracy.
Ask everyone firstNothing is stored for anyone until your banner grants it. Needs the wiring above.Visitors who do not answer stay cookieless.
Never use cookiesNo device storage for anyone, so no banner is needed at all.Same-day attribution only - no first touch, no multi-day journeys.

Switching to Never also clears cookies already on returning visitors' devices, the next time they load a page.

Excluding yourself#

Visit any tracked page once with ?chartsy_ignore=1:

https://yoursite.com/?chartsy_ignore=1

That browser is never tracked again - no cookies, no events, nothing counted against your plan. Use ?chartsy_ignore=0 to undo it. Do this on each browser and device you use to check your own site. Traffic from private and internal IP addresses is excluded automatically.

Troubleshooting#

Every signup says "Unknown source"

Almost always the script is missing from the page where visitors first arrive. If your marketing site and app are on different subdomains, the script has to be on both - the crossing between them is internal navigation, so if the marketing side never recorded the original visit, there is nothing left to attribute. Check the banner too: if the script is gated behind consent, it never runs for the majority of people, who never answer.

No data at all

Check, in order:

  • The domain is registered under Settings → Domains
  • The script renders in <head> on the page you are testing
  • You are not on localhost without data-allow-localhost="true"
  • You have not opted this browser out
  • No ad blocker or content blocker is active

It worked, then stopped after a site change

Most often a JavaScript optimisation feature - "combine scripts", "defer JavaScript", "minify and inline" - in a caching or speed plugin, or a build step that rewrites script tags. Chartsy reads its settings off its own <script> tag, so anything that strips its attributes or inlines it without them leaves it running with no key, measuring nothing. Exclude track.js from combining, deferring and inlining.

Visits but no signups

Step 2 is not wired, or your signup goes through OAuth and needs the server-side call.

Signups but no revenue

Link a payment account to the site under Settings → Domains, and check step 3 - without the metadata, matching falls back to email, which fails when billing and signup addresses differ.

Fewer visits than another analytics tool

Expected. Chartsy counts one visit per session per source, not one per pageview, and excludes bots, internal IPs and opted-out browsers.

What gets collected#

Page URLs and referrers, UTM parameters, the landing page, and the last few pages of the session that converted. Country, derived from the IP address. A visitor identifier - either a first-party cookie or, in cookieless mode, a server-side hash that rotates every 24 hours. At signup, the email address your own code passes.

No biometric data. No third-party cookies. No ad networks. IP addresses are not stored on any attribution record - they are used in flight to resolve a country, limit abuse and compute the identifier, then dropped. The identifier is scoped per site, so the same person visiting two different Chartsy customers is two unrelated records.

Related articles

Chartsy Team

Written by

Chartsy Team

The Chartsy Team writes guides, product updates, and resources to help SaaS and eCommerce founders make sense of their metrics, without SQL or spreadsheets.

Chartsy
Ministry of Economy and Innovation
Startup Albania

The Chartsy program is realized with the financial support of the Albanian Government through the Ministry of Economy and Innovation, under the Grant 2026 scheme, and is implemented by the Innovation4Albania Agency.