> ## Documentation Index
> Fetch the complete documentation index at: https://docs.permutive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tracking Off-Site Events with Pixels

> How to track conversions, email opens, and ad impressions that occur outside your website

## Overview

Off-site tracking allows you to capture events that happen beyond your website—such as partner site conversions, email opens, or ad impressions—and associate them with your users in Permutive. This enables powerful use cases like:

* **Campaign reporting**: Measure the effectiveness of advertising campaigns by tracking conversions on partner sites
* **Campaign optimization**: Optimize targeting during campaigns to reach conversion KPIs
* **Suppression targeting**: Remove users from targeting cohorts once they have converted
* **Premium targeting**: Offer premium targeting for users who have visited a partner site but not yet converted

<Info>
  **Prerequisites:**

  * A custom event schema must exist in your Permutive workspace before implementation. Contact [Support](mailto:support@permutive.com) to set this up.
  * Determine which user identification method you'll use (third-party cookies, internal user IDs, or Permutive user ID).
</Info>

## User Identification Methods

Before implementing tracking pixels, choose how you'll identify users:

**Third-party cookies**: Use IDs from partners like AppNexus, Google, or The Trade Desk. Permutive can automatically collect some third-party cookies—contact [Support](mailto:support@permutive.com) if you're unsure whether your preferred ID is supported.

<Note>
  Some browsers block third-party cookies, which limits this method's effectiveness. Consider using internal user IDs or Permutive's user ID for more reliable tracking.
</Note>

**Internal user IDs**: Use Permutive's identity framework with your own identifiers to track users across touchpoints.

**Permutive user ID**: Use the Permutive-assigned user ID directly for tracking.

## Implementation Approaches

Choose the approach that best fits your use case:

<Tabs>
  <Tab title="Tracking URL">
    Use this method when you need to copy and paste a tracking URL into third-party platforms like ad servers. The platform will handle firing the pixel request.

    Run these JavaScript snippets in your browser console to generate tracking URLs.

    <Steps>
      <Step title="Using AppNexus ID">
        This example uses the AppNexus third-party cookie for user identification.

        ```javascript theme={"dark"}
        // Configuration
        const publicKey = 'your-public-api-key';
        const eventName = 'PartnerConversion';
        const eventProperties = {
          partner: 'Example Partner',
          value: 50.0
        };

        // Generate the tracking URL
        const baseUrl = 'https://api.permutive.app/v2.0/px/track';
        const params = new URLSearchParams({
          k: publicKey,
          e: eventName,
          p: JSON.stringify(eventProperties),
          it: 'appnexus',
          rand: Math.round(Math.random() * 1000000)
        });

        const trackingUrl = `https://ib.adnxs.com/getuid?${encodeURI(`${baseUrl}?${params}`)}&i=$UID`;
        console.log(trackingUrl);
        ```

        **Example output:**

        ```
        https://ib.adnxs.com/getuid?https://api.permutive.app/v2.0/px/track?k=your-public-api-key&e=PartnerConversion&p=%7B%22partner%22%3A%22Example+Partner%22%2C%22value%22%3A50%7D&it=appnexus&rand=123456&i=$UID
        ```

        <Note>
          **GDPR Compliance for EU Users:** When targeting users in the EU, you must append GDPR parameters to the AppNexus URL. If TCF signals are available, include `gdpr` (1 if GDPR applies, 0 if not) and `gdpr_consent` (the consent string). If TCF signals are unavailable, use `consent=1` (user consented) or `consent=0` (no consent). Without these parameters, AppNexus will not return the user ID for EU users.

          Example with GDPR parameters:

          ```
          https://ib.adnxs.com/getuid?...&gdpr=1&gdpr_consent=YOUR_CONSENT_STRING
          ```
        </Note>
      </Step>

      <Step title="Using Internal User ID">
        This example uses your own identifier via Permutive's identity framework.

        ```javascript theme={"dark"}
        // Configuration
        const publicKey = 'your-public-api-key';
        const eventName = 'PartnerConversion';
        const identifierValue = 'your-user-id';
        const identifierTag = 'your-identifier-tag';
        const eventProperties = {
          partner: 'Example Partner',
          value: 50.0
        };

        // Generate the tracking URL
        const baseUrl = 'https://api.permutive.app/v2.0/px/track';
        const params = new URLSearchParams({
          k: publicKey,
          i: identifierValue,
          e: eventName,
          p: JSON.stringify(eventProperties),
          it: identifierTag,
          rand: Math.round(Math.random() * 1000000)
        });

        const trackingUrl = `${baseUrl}?${params}`;
        console.log(trackingUrl);
        ```

        **Example output:**

        ```
        https://api.permutive.app/v2.0/px/track?k=your-public-api-key&i=your-user-id&e=PartnerConversion&p=%7B%22partner%22%3A%22Example+Partner%22%2C%22value%22%3A50%7D&it=your-identifier-tag&rand=123456
        ```
      </Step>

      <Step title="Using Permutive User ID">
        This example uses the Permutive-assigned user ID directly.

        ```javascript theme={"dark"}
        // Configuration
        const publicKey = 'your-public-api-key';
        const eventName = 'PartnerConversion';
        const userId = 'permutive-user-id';
        const eventProperties = {
          partner: 'Example Partner',
          value: 50.0
        };

        // Generate the tracking URL
        const baseUrl = 'https://api.permutive.app/v2.0/px/track';
        const params = new URLSearchParams({
          k: publicKey,
          u: userId,
          e: eventName,
          p: JSON.stringify(eventProperties),
          rand: Math.round(Math.random() * 1000000)
        });

        const trackingUrl = `${baseUrl}?${params}`;
        console.log(trackingUrl);
        ```

        **Example output:**

        ```
        https://api.permutive.app/v2.0/px/track?k=your-public-api-key&u=permutive-user-id&e=PartnerConversion&p=%7B%22partner%22%3A%22Example+Partner%22%2C%22value%22%3A50%7D&rand=123456
        ```
      </Step>
    </Steps>

    <Tip>
      Some platforms provide a macro for the `rand` (cache-buster) parameter. Check your platform's documentation to see if you can use their macro instead of generating a random number.
    </Tip>
  </Tab>

  <Tab title="JavaScript Tag">
    Use this method when you can deploy JavaScript on the page where the event occurs, such as on partner conversion pages, within iframes, or in video players.

    <Steps>
      <Step title="Deploy the JavaScript Tag">
        Add the following script to the page where you want to track the event. This example uses AppNexus for user identification.

        ```html theme={"dark"}
        <script>
        (function() {
          // Configuration
          const publicKey = 'your-public-api-key';
          const eventName = 'PartnerConversion';
          const eventProperties = {
            partner: 'Example Partner',
            url: window.location.href
          };

          // Fire the tracking pixel
          const baseUrl = 'https://api.permutive.app/v2.0/px/track';
          const params = new URLSearchParams({
            k: publicKey,
            e: eventName,
            p: JSON.stringify(eventProperties),
            it: 'appnexus',
            rand: Math.round(Math.random() * 1000000)
          });

          const pixelUrl = `https://ib.adnxs.com/getuid?${encodeURI(`${baseUrl}?${params}`)}&i=$UID`;
          new Image().src = pixelUrl;
        })();
        </script>
        ```

        <Note>
          **GDPR Compliance for EU Users:** When targeting users in the EU, you must append GDPR parameters to the AppNexus URL. Add `gdpr=1` and `gdpr_consent=YOUR_CONSENT_STRING` to the URL if TCF signals are available, or `consent=1` if the user has consented but TCF signals are unavailable.
        </Note>
      </Step>

      <Step title="Customize Event Properties">
        You can dynamically populate event properties based on the page context. For example:

        ```javascript theme={"dark"}
        const eventProperties = {
          partner: 'Site A',
          value: 50.0,
          product_category: 'Electronics',
          url: window.location.href
        };
        ```

        <Tip>
          The same JavaScript tag can be used across multiple partner sites—the partner name can be inferred from the URL property if needed.
        </Tip>
      </Step>
    </Steps>

    <Note>
      The `rand` parameter is generated automatically in the code, ensuring each pixel fires uniquely for accurate tracking.
    </Note>
  </Tab>

  <Tab title="HTML Image Tag">
    Use this method for environments where JavaScript is not allowed, such as marketing emails.

    <Steps>
      <Step title="Generate Your Tracking URL">
        First, generate your tracking URL using the snippets from the **Tracking URL** tab. Run the appropriate JavaScript in your browser console and copy the resulting URL.
      </Step>

      <Step title="Embed in an Image Tag">
        Wrap your tracking URL in a 1x1 pixel image tag:

        ```html theme={"dark"}
        <img src="your-tracking-url-here" height="1" width="1" border="0" alt="" />
        ```

        **Full example using AppNexus:**

        ```html theme={"dark"}
        <img src="https://ib.adnxs.com/getuid?https%3A%2F%2Fapi.permutive.app%2Fv2.0%2Fpx%2Ftrack%3Fk%3Dyour-public-api-key%26i%3D%24UID%26e%3DEmailOpen%26p%3D%257B%2522campaign%2522%253A%2522Summer%2520Sale%2522%257D%26it%3Dappnexus%26rand%3D123456" height="1" width="1" border="0" alt="" />
        ```

        **Full example using Permutive User ID:**

        ```html theme={"dark"}
        <img src="https://api.permutive.app/v2.0/px/track?k=your-public-api-key&u=permutive-user-id&e=EmailOpen&p=%7B%22campaign%22%3A%22Summer%20Sale%22%7D&rand=123456" height="1" width="1" border="0" alt="" />
        ```
      </Step>
    </Steps>

    <Tip>
      Some email service providers (ESPs) offer macros for the `rand` parameter. Check your ESP's documentation to see if you can use their macro for cache-busting instead of a static value.
    </Tip>
  </Tab>
</Tabs>

## Alternative ID Sync Providers

The examples above use AppNexus for third-party cookie identification. You can also use Google or The Trade Desk for ID syncing, which work similarly but have their own URL patterns.

<Expandable title="Using Google ID Sync">
  Google's cookie sync endpoint automatically forwards custom parameters to Permutive. This allows you to track events while simultaneously syncing the Google ID.

  **Generate a Google tracking URL:**

  ```javascript theme={"dark"}
  // Configuration
  const publicKey = 'your-public-api-key';
  const permutiveUserId = 'permutive-user-id'; // Optional: include if known
  const eventName = 'AdImpression';
  const eventProperties = {
    campaign_id: 123
  };
  const gdpr = 0; // Set to 1 if GDPR applies

  // Build the tracking URL
  const params = new URLSearchParams({
    google_nid: 'permutive_dmp',
    google_cm: '',
    type: 'ddp',
    k: publicKey,
    e: eventName,
    p: JSON.stringify(eventProperties),
    gdpr: gdpr
  });

  // Optionally include Permutive user ID if known
  if (permutiveUserId) {
    params.set('u', permutiveUserId);
  }

  const trackingUrl = `https://cm.g.doubleclick.net/pixel?${params}`;
  console.log(trackingUrl);
  ```

  **Example output:**

  ```
  https://cm.g.doubleclick.net/pixel?google_nid=permutive_dmp&google_cm=&type=ddp&k=your-public-api-key&e=AdImpression&p=%7B%22campaign_id%22%3A123%7D&gdpr=0
  ```

  When this pixel fires, Google will redirect to Permutive's sync endpoint, passing along all your custom parameters plus the Google ID. The event will be tracked and the ID sync will occur automatically.

  <Note>
    **GDPR Compliance:** Include `gdpr=1` for EU users. If consent is required, also include `gdpr_consent` with the TCF consent string.
  </Note>
</Expandable>

<Expandable title="Using The Trade Desk ID Sync">
  The Trade Desk's cookie sync endpoint requires custom parameters to be passed via the `ttd_passthrough` parameter. This parameter accepts URL-encoded query params, which means event properties (JSON) must be **double URL-encoded**.

  **Generate a Trade Desk tracking URL:**

  ```javascript theme={"dark"}
  // Configuration
  const publicKey = 'your-public-api-key';
  const permutiveUserId = 'permutive-user-id';
  const eventName = 'AdImpression';
  const eventProperties = {
    campaign_id: 123
  };
  const gdpr = 1; // Set to 1 if GDPR applies
  const gdprConsent = 'YOUR_CONSENT_STRING'; // TCF consent string

  // Build the passthrough params (these get forwarded to Permutive)
  // Note: Event properties must be URL-encoded within the passthrough
  const passthroughParams = new URLSearchParams({
    e: eventName,
    p: JSON.stringify(eventProperties) // Will be encoded by URLSearchParams
  });

  // Build the full tracking URL
  // Note: ttd_puid format is <permutive_api_key>,<permutive_user_id>
  const params = new URLSearchParams({
    ttd_pid: 'dbegppc',
    ttd_tpi: '1',
    ttd_puid: `${publicKey},${permutiveUserId}`,
    ttd_passthrough: passthroughParams.toString(), // Already URL-encoded
    gdpr: gdpr,
    gdpr_consent: gdprConsent
  });

  const trackingUrl = `https://match.adsrvr.org/track/cmf/generic?${params}`;
  console.log(trackingUrl);
  ```

  **Example output:**

  ```
  https://match.adsrvr.org/track/cmf/generic?ttd_pid=dbegppc&ttd_tpi=1&ttd_puid=your-public-api-key%2Cpermutive-user-id&ttd_passthrough=e%3DAdImpression%26p%3D%257B%2522campaign_id%2522%253A123%257D&gdpr=1&gdpr_consent=YOUR_CONSENT_STRING
  ```

  When this pixel fires, The Trade Desk will redirect to Permutive's sync endpoint, passing along the decoded passthrough parameters plus the Trade Desk ID. The event will be tracked and the ID sync will occur automatically.

  <Note>
    **Double Encoding Explained:** The `ttd_passthrough` value is URL-encoded by `URLSearchParams`. Since the event properties (`p`) contain JSON that is also URL-encoded, the final result has the JSON double-encoded. This is expected behavior—The Trade Desk will decode it once, and Permutive will decode it again.
  </Note>

  <Note>
    **GDPR Compliance:** Include `gdpr=1` and `gdpr_consent` with the TCF consent string for EU users.
  </Note>
</Expandable>

## Verifying Your Implementation

After implementing your tracking pixel:

1. Navigate to the **Events** section in your Permutive dashboard
2. Look for your custom event name (e.g., "PartnerConversion")
3. Allow some time for events to appear after implementation

If you don't see events appearing, double-check your configuration and ensure the event schema has been created in your workspace.

## Common Use Cases

Off-site tracking pixels are commonly used for:

* **PartnerConversion events**: Track when users convert on partner sites to measure campaign effectiveness
* **EmailOpen events**: Track email opens from marketing campaigns to build engagement audiences
* **AdImpression events**: Track ad views in iframes or video players for frequency capping and reporting
* **Custom events**: Track any off-site user behavior relevant to your business

## Next Steps

<CardGroup cols={2}>
  <Card title="Contact Support" icon="envelope" href="mailto:support@permutive.com">
    Get help setting up custom event schemas or troubleshooting pixel implementation
  </Card>

  <Card title="Back to Signals" icon="arrow-left" href="/products/signals">
    Return to Signals product overview
  </Card>
</CardGroup>
