> ## Documentation Index
> Fetch the complete documentation index at: https://help.get-ryze.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Ryze Pixel

> One script on your site. Ryze routes every event to Meta, Google Ads, TikTok and GA4 server-side.

Ryze Pixel collects events from your website and forwards them to your ad platforms from Ryze's servers. You install one script tag; Ryze handles the Conversions API for Meta, conversion uploads for Google Ads, the Events API for TikTok and the Measurement Protocol for GA4. Server-side delivery survives ad blockers and browser tracking limits, and every destination shows sent versus received counts so you can see what actually landed.

The pixel lives in your workspace under **Events**.

## Install the script

The fastest path is **Install → Install with Agent** on the Web Analytics page: the agent checks which CMS is connected (Shopify, WordPress, Webflow or GitHub), places the script tag before `</head>` itself and confirms it is served. If no writable CMS is connected it gives you the exact place to paste it. To do it by hand:

<Steps>
  <Step title="Open Events and click Install manually">
    The dialog shows your script tag with the workspace's public key (`data-key="rz_pk_…"`). Copy it.
  </Step>

  <Step title="Paste it before </head> on every page">
    ```html theme={null}
    <script async src="https://px.get-ryze.ai/px.js" data-key="rz_pk_YOUR_KEY"></script>
    ```

    On most site builders this goes into the global head or custom code section. On Shopify, add it to `theme.liquid` right before `</head>`; the theme does not run on the checkout and thank-you pages of most stores, so purchases there come from your backend through the server API below.

    If you load the script asynchronously and call `ryze` before it has loaded, queue the calls: `window.ryzeq = window.ryzeq || []; ryzeq.push(["track", "lead"]);` The script replays the queue when it starts.

    Script attributes: `data-consent="required"` holds every event and cookie until `ryze.consent("grant")` (see Consent); `data-link-domains="checkout.example.com"` keeps the visitor and session across links to another domain, for example a hosted checkout; `data-hash-routing="on"` counts hash changes as page views; `data-track-search="on"` makes a different query string a different page (by default a filter or sort is the same page); `data-autocapture="off"` disables click and form capture; `data-allow-localhost="on"` tracks local development, which is otherwise ignored.
  </Step>

  <Step title="Add your domains under Allowed domains">
    Events from any other host are dropped. Add every domain that serves the script, including staging if you want test traffic.
  </Step>

  <Step title="Wait for the first event">
    Open your site once. The dialog switches from **Waiting for the first event…** to **First event received**, and the Events page starts filling.
  </Step>
</Steps>

## What the script captures

Page views, clicks and form submissions are captured automatically as plain interaction events: the click label and link, the form id and submit button text. The script never reads what visitors type and never decides on its own that something was a conversion. Conversions come from `ryze.track` or the server API. Standard ecommerce and lead events are recognized by name and mapped to each platform's standard events:

`page_view`, `view_content`, `add_to_cart`, `add_to_wishlist`, `view_cart`, `remove_from_cart`, `initiate_checkout`, `add_payment_info`, `purchase`, `refund`, `lead`, `complete_registration`, `subscribe`, `contact`, `start_trial`, `schedule`, `search`, `login`.

`refund` takes the `order_id` of the original purchase, the amount returned as `value` with its `currency`, and optionally the returned lines as `contents`. Google Ads receives it as an adjustment of the original conversion (a retraction when the whole order is returned, a restatement otherwise; Google accepts adjustments between 24 hours and 54 days after the purchase), GA4 as a `refund` event. Meta and TikTok have no refund event and receive nothing.

## Identify visitors and track your own events

Once the script is loaded, `ryze` is available on the page.

```js theme={null}
ryze.identify({ email: "jane@example.com", phone: "+14155550100" });
ryze.track("purchase", { value: 129, currency: "USD", order_id: "48213" });
ryze.track("DemoBooked", { plan: "pro" });
```

* `ryze.identify` attaches who the visitor is to the session. It accepts `email`, `phone`, `first_name`, `last_name`, `city`, `state`, `zip`, `country`, `gender`, `birthdate` and `external_id`; every value is normalized and hashed in the browser before it leaves the page, and the more of them you pass the better the match rate on every platform. Pass `country` whenever you know it, it is what turns a local phone number into an international one. Call it as soon as you know who the visitor is: after login, on checkout, after a form submit.
* `ryze.track` sends any event. Use a standard name from the list above to get the platform mapping for free, or your own name for custom events. Custom events show up on the Events page and can be mapped per destination.

## Consent

By default the script starts tracking on load and sets its first-party cookies immediately. If your visitors need to opt in first, add `data-consent="required"` to the script tag: nothing is sent and no cookie is written until you call `ryze.consent("grant")`. Events fired before the grant are held in memory and sent afterwards in order, so a purchase that happens while the banner is open is not lost. `ryze.consent("revoke")` stops tracking, clears the stored identity and removes the Meta cookies. Granular consent works too: `ryze.consent({ analytics: true, marketing: false })` keeps analytics running but captures no click ids, writes no `_fbp`/`_fbc`, and marks every event so it is never forwarded to an ad platform; `sale_of_data: "ldu"` turns on Meta's Limited Data Use for CCPA traffic.

A browser with Global Privacy Control enabled is always treated as revoked and cannot be overridden. Do Not Track is honoured only when you add `data-respect-dnt="on"` to the script tag: it has no legal weight and most browsers have dropped it, so by default it does not cost you conversions. `ryze.reset()` starts a new anonymous visitor on the device, for example on logout, and drops the previous person's hashed identifiers and click ids. `ryze.identity()` returns the current anonymous id, session, Meta cookies and click ids for a page that wants to pass them to its own server. `window.ryzeBeforeSend = (event) => event` lets you edit or drop (return `null`) an event before it is captured.

## Server-to-server purchases

Send purchases from your backend when the browser cannot be trusted to fire them, for example after payment confirmation or for subscription renewals. The secret key is in **Install manually → Server-to-server**. Never ship it to the browser.

```bash theme={null}
curl -X POST https://px.get-ryze.ai/s2s \
  -H "x-ryze-key: rz_pk_YOUR_PUBLIC_KEY" \
  -H "Authorization: Bearer rz_sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"events":[{"event":"purchase","order_id":"48213","value":129,"currency":"USD",
       "user":{"email":"jane@example.com","phone":"+14155550100"},
       "contents":[{"id":"sku-1","quantity":1,"item_price":129}]}]}'
```

Every event needs an `event_id`, an `order_id` or a `timestamp` (epoch milliseconds, at most 7 days in the past and one hour in the future); Ryze builds a stable id from them, so a retried webhook counts once. Use `order_id` on every purchase: a purchase that fires both in the browser and from your backend counts once, and Ryze merges the two, keeping the browser's session and click ids and adding your match keys. Optional fields: `anonymous_id`, `session_id`, `fbp`, `fbc` and `click` (as returned by `ryze.identity()`), `ip` and `user_agent` of the buyer (pass them, Meta requires the user agent to accept a website event), `url`, `contents`, `content_ids`, `content_type`, `num_items`, `properties`. The response is `{ accepted, rejected }`; a `400` names the event and the rule it broke, a `429` carries `Retry-After`, and a `5xx` should be retried with the same body, it is safe. Rotate the secret from the same dialog if it ever leaks; the old key stops working immediately.

## Add destinations

Destinations are where events go. Ryze uses the ad accounts already connected under **Integrations**, so connect Meta, Google Ads, TikTok or GA4 there first.

1. On Events, click **Add destination** and pick a platform.
2. Choose the account and, for Meta and TikTok, the dataset or pixel. **Create new "Ryze Pixel"** lets Ryze create one through the API so you do not touch Events Manager.
3. Events are mapped to the platform's standard events by default. Click **Customize** to change a mapping, send a custom name, or stop sending a specific event.
4. Click **Enable destination**, then **Send test event**. Meta and TikTok accept a test event code so the test never counts as real.

Per platform:

* **Meta** — Conversions API into a dataset in your ad account. Optional test event code from Events Manager → Test events.
* **Google Ads** — conversion upload with gclid, gbraid and wbraid plus enhanced conversions. Ryze creates the conversion actions it needs. Google only accepts a conversion once its click is six hours old, so uploads run six hours after each event.
* **TikTok Ads** — Events API. Paste the access token generated on the pixel (Events Manager → your pixel → Settings → Events API).
* **Google Analytics 4** — Measurement Protocol into your data stream. Paste the API secret from Admin → Data streams → Measurement Protocol API secrets. GA4 sends no delivery receipts, so a sent event means Google accepted the request.

## Reading the Events page

* **Events · 24h**, **Identified sessions**, **Purchases · 24h** and **Delivery** summarize the last day.
* **Destinations** shows sent and received per platform with a health status. Click a row for the daily chart, the event mapping and recent deliveries with error codes.
* **By event** shows every event name, its count and how it lands on each enabled destination.
* Pause a destination with its switch. Events keep collecting; routing resumes when you switch it back on.

## Troubleshooting

* **Waiting for the first event never changes** — the script is not on the page, or the host is not in Allowed domains. Check the browser console for a request to `px.get-ryze.ai`.
* **Sent but not received** — open the destination and read the error code on the failed deliveries. Expired tokens and missing permissions are the usual causes; reconnect the integration and retry.
* **Purchases double-count** — pass the same `order_id` from the browser and from the server.
