# Add analytics and ad tags to your storefront

> Turn on Google Analytics 4 and the pixels for Google Ads, Meta, TikTok, Microsoft, Reddit, X and Tag Manager, and check that each one receives visits.

Source: https://www.coritan.com/docs/organizations/tags/

In the dashboard:

- /dashboard/organizations/…/settings/tags: https://www.coritan.com/dashboard/organizations

A *tag* is a small piece of code from an analytics or advertising platform. It tells the platform which visits and sales came from its own ads, so you can measure what the ads earn. Your storefront loads a tag for each platform whose ID you save, and for no other.

Every tag is an ID. You copy it from the platform, paste it into one field and save. The IDs are public: they appear in the source of every storefront page, so they are not secrets, and this page never asks for a password or an API key.

## Before you begin

- You need the Owner or Admin role in the organization.
- You need an account on each platform you want to use, with its tag or pixel already created.
- Your storefront must be served by Coritan. A site you build yourself on the [Organization API](/docs/organizations/storefront/) reads the same IDs from the [Storefront API](/docs/organizations/storefront/storefront-api/) and loads the tags itself.

## Where to set the tags

In the [dashboard](https://www.coritan.com/dashboard/organizations), open your organization, then "Settings", then "Tags and pixels". The page has one card for each platform, with a badge that says "On" when an ID is saved and "Off" when it is not. A member below the Admin role sees the saved IDs and nothing to press.

1. Paste each platform's ID into its card. The field shows an example of the shape the ID has.
2. Select "Clear" on a card to empty that platform's fields.
3. Select "Save changes" on the card. Each card saves on its own, and "Discard" puts the card back as it was.

The staff console has the same editor at `/staff/settings?tab=marketing`: the "Settings" page and its "Marketing" tab. Its "Tags and pixels" section has one panel for each platform, and a single "Save tags" button saves every panel at once. It is open to the Admin and Owner roles only. Platform staff also set the tags for any organization in the admin console.

Each ID is checked as you save. A wrong one is refused with a sentence that names the field, such as `Meta pixel id must be 8 to 20 digits`, and nothing is saved. Saving what is already stored changes nothing. A change reaches new page loads within a minute, and the [audit log](/docs/organizations/audit-log/) records it as `settings.tags.updated` with the IDs before and after. You can also set the tags with the [API](#with-the-api).

## Result

View the source of a storefront page. A script in the head sets `window.__ctTags` to the IDs you saved, with the consent settings after them, and a platform you left empty is missing from it. The platform's own library then loads once the visitor interacts with the page and allows the platform's kind of cookie.

## Find each ID

| Platform | Field | Looks like | Where to find it |
| --- | --- | --- | --- |
| Google Analytics 4 | Measurement ID | `G-ABC123DEF4` | In Google Analytics, open Admin, Data streams, then your web stream. |
| Google Ads | Conversion ID | `AW-123456789` | In Google Ads, open Goals, Conversions, then a conversion action and its tag setup. |
| Google Ads | Conversion labels | `AbCdEfGhIjKlMn` | In the same tag setup, the part of the event snippet after the slash. Add one for a purchase, a sign-up and a lead. |
| Meta | Pixel ID | `123456789012345` | In Meta Events Manager, open your data source. |
| TikTok | Pixel ID | `C1A2B3C4D5E6F7G8H9J0` | In TikTok Events Manager, open your web events. |
| Microsoft Advertising | UET tag ID | `12345678` | In Microsoft Advertising, open Conversion tracking, then UET tags. |
| Reddit | Pixel ID | `t2_abc123` | In Reddit Ads, open Events Manager. |
| X | Pixel ID and event IDs | `o1abc`, `tw-o1abc-o2def` | In X Ads, open Events manager. An event ID starts with `tw-`. |
| Google Tag Manager | Container ID | `GTM-ABC123` | In Google Tag Manager, the ID at the top of your workspace. |

Google Analytics 4 also has a "Debug mode" switch, which is off by default. Turn it on while you test, and off again afterwards.

Labels and event IDs belong to the ID above them. You cannot save Google Ads labels without a conversion ID, or X event IDs without a pixel ID.

## Set up Google Analytics 4

Two settings in Google Analytics keep the numbers honest. Both are under Admin, then Data streams, then your web stream.

1. Open "Enhanced measurement", then the settings of "Page views", and show the advanced settings. Turn off "Page changes based on browser history events". The storefront sends its own page view when a visitor moves to another page, and with this switch on, Google Analytics counts each move twice.
2. Open "Configure tag settings", show all settings, and open "List unwanted referrals". Add `stripe.com` and `paypal.com`, and the address of any other payment page your customers pass through, such as `paynow.gg`. Without them, a customer who comes back from paying shows as a visit from the payment page, and the sale is credited to it instead of to the ad.

To check it, turn on "Debug mode", open your storefront in a new tab, and open DebugView under Admin in Google Analytics. Your visit and each page you open appear there. Turn "Debug mode" off when you are done.

## Check the other platforms

Each platform has its own test tool. Open your storefront in a browser window, accept marketing cookies when the banner asks, then look in the platform:

- Google Ads and Google Tag Manager: use Tag Assistant, which lists the tags a page loaded. For Tag Manager, use the container's preview mode.
- Meta: the "Test events" tab in Events Manager shows the events from your site while you browse it.
- TikTok: the test events view in Events Manager lists the events the pixel received.
- Microsoft Advertising: the UET tag's status page shows whether the tag is active, and the UET Tag Helper browser extension shows each hit.
- Reddit and X: use the platform's pixel helper browser extension, or the events page in its ads manager.

If a tag shows nothing, work down [Troubleshooting](#troubleshooting).

## Events

Besides each page view, the storefront tells the tags what a visitor does on the way to buying. Every event uses the name Google Analytics 4 gives it, and the tag for each other platform turns it into that platform's own event. An event reaches a platform only when its tag is on and the visitor allows its kind of cookie. Google Analytics 4 hears every event, with its consent set as the visitor chose. Google Ads counts `purchase`, `sign_up` and `generate_lead` as conversions when its card has a label for them.

| Event | When it is sent | Parameters |
| --- | --- | --- |
| `view_item_list` | A list of plans shows its plans for the first time on a page. | `item_list_name` and `items`, each with its `index` in the list. |
| `select_item` | A visitor presses the button on a plan or product card. | `item_list_name` and the chosen item. |
| `view_item` | A plan or product page opens, once for each plan in a visit. | `currency`, `value` and the item. |
| `begin_checkout` | A visitor first touches the order form of a paid plan, or presses its order button, whichever comes first. Once for each page view. A free plan has no checkout and sends none. | `currency`, `value` (the price after a coupon), `coupon` and the item. |
| `add_payment_info` | The buyer first picks a way to pay on the invoice page: card, PayPal, crypto, account balance, or Apple Pay and Google Pay. Once for each invoice in a page view. | `payment_type`, `currency`, `value` and the invoice's items. |
| `purchase` | The invoice page shows the invoice paid, in the browser that paid it. | `transaction_id`, `currency`, `value`, `tax`, `coupon` and the invoice's items. |
| `generate_lead` | A visitor places an order that costs nothing, such as a free server, or sends a contact, quote or sales form. | `value` of 0, and the item for an order. |
| `sign_up` | An account is created. | `method`: how it was made, such as `email`, `discord` or `google`. |
| `login` | A visitor signs in. | `method`: how they signed in, such as `email`, `password` or `google`. |

Each item has `item_id` (the plan's slug or the product's ID), `item_name`, `item_category` (the game or product family), `item_variant` (the location the buyer chose, or the billing period), `price`, `quantity` and, in a list, `item_list_name` and `index`. A price is the amount the page showed, in the currency the customer pays in. Currencies are never added together.

### How a purchase is counted

The `transaction_id` of a purchase is the invoice number, and the event ID is `purchase:` followed by the invoice number, such as `purchase:INV-000042`. A platform that receives the same sale from another source can use the event ID to count it once.

- A browser sends the purchase of an invoice once. It remembers that in the browser's local storage, so a reload, a second tab or a return visit sends nothing more.
- Only the browser that paid sends it. The invoice page counts a browser as the payer when it showed that invoice unpaid, or when the visitor comes back from the payment page with `paid=1` in the address and the invoice is confirmed paid. An address alone never counts.
- A paid invoice opened from an email link sends nothing, because that browser did not pay.
- An order that costs nothing is a lead, never a purchase.

### Who is signed in

After a visitor signs in or signs up, the storefront gives the tags the customer ID before it sends `login` or `sign_up`. Google Analytics 4 gets it as a SHA-256 hash in `user_id`, only when the visitor allows analytics. Meta, TikTok and Reddit get the hash of the ID and of the email, only when the visitor allows marketing. No platform gets a raw ID. For Google Ads enhanced conversions, a `purchase` or `sign_up` also passes the customer's email to the Google tag when the page already holds the address and the visitor allows marketing, and that tag hashes it before it leaves the browser.

### Where no event is sent

The storefront's `/staff`, `/admin` and `/dashboard` pages send none, and neither does any page on a host that is not the storefront's own.

### Check the events in Google Analytics 4

1. Turn on "Debug mode" in the Google Analytics 4 card, as described under [Set up Google Analytics 4](#set-up-google-analytics-4).
2. Open your storefront in a new tab, accept analytics when the banner asks, and open DebugView under Admin in Google Analytics.
3. Open a plan list, choose a plan, change a field of its order form and place the order. DebugView shows `view_item_list`, `select_item`, `view_item` and `begin_checkout` as they happen, each with its parameters.
4. Choose a way to pay on the invoice page. DebugView shows `add_payment_info`. Pay the invoice, and it shows `purchase` with the invoice number as its transaction ID.
5. To see a purchase again, pay a new invoice. The same invoice never sends a second purchase from the same browser.

In Meta's "Test events" tab, a purchase appears as `Purchase` with the event ID, and the TikTok test events view lists it as `CompletePayment`. Turn "Debug mode" off when you have finished.

## What visitors see

Ad tags load only after a visitor allows marketing cookies. The storefront asks, and remembers the answer for six months in the `_ct_consent` cookie. The cookies the storefront's own tracker sets are listed under [What the tracker records](/docs/organizations/traffic/#what-the-tracker-records).

- In the EEA, the UK and Switzerland, a banner asks first. Until the visitor chooses, analytics and marketing are both off, and no tag loads. The banner offers "Accept all", "Reject all" and a way to choose analytics and marketing separately.
- Everywhere else, both are on until the visitor says otherwise, and a short notice with an "Opt out" link tells them so.
- A browser that sends Global Privacy Control counts as saying no to marketing everywhere, whatever the banner says.
- A "Cookie settings" link in the storefront's footer lets a visitor change their mind.

The banner links to your privacy page, which is the "Privacy policy URL" in your organization's branding settings, or `/privacy` when there is none. Name the platforms you use in that policy.

## Limits

- Tags load on your storefront's own hostnames only. A test copy of the site on another address sends nothing.
- Tags never load on the storefront's `/staff` and `/admin` pages, and those pages allow no advertising hosts.
- The storefront allows connections only to the hosts of the platforms you save. A platform that you load through a Google Tag Manager container also needs its own ID here, so that the page allows its hosts.
- A brand that set Google Analytics before tags existed keeps working. The Google Analytics 4 card shows a note, and the first save moves the ID into the new settings.

## Troubleshooting

`Meta pixel id must be 8 to 20 digits`
: Each platform names the shape its ID has. Copy the ID again from the platform, without spaces around it. The sentence and the `field` in the API answer say which input to fix.

`Add the Google Ads conversion id before its conversion labels`
: Save the conversion ID with the labels, or remove the labels.

`Add the X pixel id before its event ids`
: Save the pixel ID with the event IDs, or remove the event IDs.

A tag shows no visits
: Check, in this order: the panel says "On" and you saved it; a minute has passed; you opened the storefront on its own address; you accepted marketing cookies, or you are outside the EEA, the UK and Switzerland and did not opt out; and no browser extension or privacy setting blocks the platform.

The same sale counts twice in Google Analytics
: Turn off "Page changes based on browser history events" as described under [Set up Google Analytics 4](#set-up-google-analytics-4).

Sales are credited to Stripe or PayPal
: Add the payment pages to the list of unwanted referrals, as described under [Set up Google Analytics 4](#set-up-google-analytics-4).

## With the API

An owner or admin reads and replaces the tags with an access token, sent as `Authorization: Bearer $CORITAN_TOKEN`. Any member can read them with `GET /api/v1/orgs/{org_slug}/tags`. `PUT` takes the whole `tags` object: a platform you leave out is turned off.

```bash title="Turn on Google Analytics 4 and Meta"
curl -X PUT "https://api.coritan.com/api/v1/orgs/acme/tags" \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tags": {"ga4": {"measurement_id": "G-ABC123DEF4"}, "meta": {"pixel_id": "123456789012345"}}}'
```

The answer has the saved `tags`, the platforms an editor can draw in `kinds` (each with its `fields`, a `label`, a `hint`, a `pattern` and an `example`), the `consent` settings, `legacy_google_analytics` and, after a `PUT`, `changed`: the platforms that differ from before.

```json
{
  "tags": {
    "ga4": { "measurement_id": "G-ABC123DEF4", "debug": false },
    "meta": { "pixel_id": "123456789012345" }
  },
  "consent": { "banner": true, "privacy_path": "/privacy" },
  "legacy_google_analytics": false,
  "changed": ["ga4", "meta"]
}
```

| Platform | Key | Fields |
| --- | --- | --- |
| Google Analytics 4 | `ga4` | `measurement_id`, `debug` (`true` or `false`) |
| Google Ads | `google_ads` | `conversion_id`, `labels` with `purchase`, `sign_up` and `lead` |
| Meta | `meta` | `pixel_id` |
| TikTok | `tiktok` | `pixel_id` |
| Microsoft Advertising | `microsoft` | `uet_id` |
| Reddit | `reddit` | `pixel_id` |
| X | `x` | `pixel_id`, `events` with `purchase`, `sign_up` and `lead` |
| Google Tag Manager | `gtm` | `container_id` |

IDs are trimmed, and each is checked against its platform's shape: Google Analytics 4 `G-` then 6 to 20 letters or digits, Google Ads `AW-` then 6 to 14 digits, Meta 8 to 20 digits, TikTok 10 to 32 letters or digits, Microsoft 6 to 12 digits, Reddit 6 to 40 letters, digits, dashes or underscores, X 4 to 12 lowercase letters or digits, Tag Manager `GTM-` then 4 to 10 letters or digits. A platform with no ID is left out. Keys the API does not know are dropped.

A bad ID answers `422` with `detail`, the sentence to show, and `field`, the input it belongs to:

```json
{ "detail": "Meta pixel id must be 8 to 20 digits", "field": "meta.pixel_id" }
```

Staff console members with the Admin role use the same two routes under `/api/v1/orgs/{org_slug}/staff/marketing/tags`, which also refuse a read from any other role. The older `google_analytics` field of `PATCH /api/v1/orgs/{org_slug}/settings` still works: it sets the Google Analytics 4 entry of `tags`.

## Related

- [Change organization settings](/docs/organizations/settings/)
- [Read your storefront's traffic](/docs/organizations/traffic/)
- [Build a storefront on the Organization API](/docs/organizations/storefront/)
- [Read the organization audit log](/docs/organizations/audit-log/)

## Next steps

- [Read your storefront's traffic](/docs/organizations/traffic/) to compare Google Analytics with what Coritan counts on its own.
- [Name the platforms in your privacy policy](/docs/organizations/settings/#change-the-branding-and-legal-details), through the privacy policy URL in your branding.

## API

- `GET /api/v1/orgs/{org_slug}/tags`: The tags the storefront loads, and what an editor needs to draw them (https://www.coritan.com/docs/api/reference/organizations/organizations-members/tags/#op-get-api-v1-orgs-org-slug-tags)
- `PUT /api/v1/orgs/{org_slug}/tags`: Replace the tags the storefront loads with the ones sent (https://www.coritan.com/docs/api/reference/organizations/organizations-members/tags/#op-put-api-v1-orgs-org-slug-tags)
- `GET /api/v1/orgs/{org_slug}/staff/marketing/tags`: The tags the storefront loads, and what an editor needs to draw them (https://www.coritan.com/docs/api/reference/organizations/org-staff-marketing/staff/#op-get-api-v1-orgs-org-slug-staff-marketing-tags)
- `PUT /api/v1/orgs/{org_slug}/staff/marketing/tags`: Replace the tags the storefront loads with the ones sent (https://www.coritan.com/docs/api/reference/organizations/org-staff-marketing/staff/#op-put-api-v1-orgs-org-slug-staff-marketing-tags)
