---
title: Tracking snippets
description: The three JavaScript snippets for landing pages — cookie enrichment, direct-link click creation, and firing a conversion from a thank-you page.
updated: 2026-07-30
order: 2
related: [/reference/postback, /guides/first-campaign, /concepts/attribution]
---

Three scripts, for three different jobs on your own pages. You get the exact
snippet for your account, with ids filled in, from
[Direct Links](https://app.postbackx.com/direct-links) and
[Landing Pages](https://app.postbackx.com/landing-pages) in the app — this page is
the reference for what each option does.

> The JavaScript objects are named `PropelDirect` and `PropelConvert`, and the HTML
> attributes are `data-propel-*`. Those names date from the platform's original
> working title. They are part of the public interface of code already running on
> live landing pages, so they cannot be renamed without breaking those pages. Type
> them exactly as shown.

## Which one you need

| You want to | Use |
| --- | --- |
| Improve Facebook match quality on a landing page that PostbackX redirects to | `Propel` — [cookie enrichment](#cookie-enrichment) |
| Point your ad straight at your own page, with no redirect | `PropelDirect` — [direct links](#direct-links) |
| Fire a conversion from your own thank-you page | `PropelConvert` — [conversion firing](#conversion-firing) |

The first two are alternatives to each other. The third is independent, and only
needed when your offer source is not sending postbacks for you.

## Cookie enrichment

For the normal flow, where your ad points at a PostbackX tracking link that
redirects to your landing page.

Facebook writes two cookies in the visitor's browser, `_fbp` and `_fbc`, that can
only be read client-side. They materially improve Facebook's ability to match a
conversion to a person, so this script reads them and attaches them to the click
record.

```html
<script src="https://propel-lander-api.propelsys.workers.dev/snippet.js"></script>
<script>
  Propel.init({
    landerId: 'YOUR_LANDER_ID',
    delay: 2500
  })
</script>
```

| Option | Default | Description |
| --- | --- | --- |
| `landerId` | | The landing page's id in PostbackX. |
| `clickIdParam` | `click_id` | The URL parameter the click id arrives in. |
| `apiUrl` | current origin | Where to send the enrichment call. |
| `delay` | `2500` | Milliseconds to wait for the Facebook pixel to load before reading its cookies. |

The delay matters: read the cookies too early and the pixel has not written them
yet. If your pixel loads slowly, raise it.

### Without writing any JavaScript

Put the attributes on any element instead, and the script initializes itself:

```html
<script src="https://propel-lander-api.propelsys.workers.dev/snippet.js"></script>
<div data-propel-auto-init
     data-propel-lander-id="YOUR_LANDER_ID"
     data-propel-click-param="click_id"
     data-propel-delay="2500"></div>
```

## Direct links

For when your ad points **directly** at your own landing page. There is no
redirect, so nothing has created a click record yet — this script creates it from
the page itself.

The trade-off: you keep full control of the URL in your ad and drop a redirect hop,
but click recording now depends on the visitor's browser running your script.

```html
<script src="https://propel-lander-api.propelsys.workers.dev/direct-snippet.js"></script>
<script>
  PropelDirect.init({
    trackingId: 'YOUR_CAMPAIGN_TRACKING_ID',
    offerId: 'YOUR_OFFER_ID',
    apiUrl: 'https://propel-lander-api.propelsys.workers.dev'
  })
</script>
```

| Option | Required | Default | Description |
| --- | --- | --- | --- |
| `trackingId` | Yes | | Your PostbackX campaign's tracking id. |
| `offerId` | Yes, unless `landerId` | | The offer to send traffic to. |
| `apiUrl` | Yes | | The lander API base URL. |
| `landerId` | No | | Use a landing page's weighted link routing instead of one fixed offer. Satisfies the `offerId` requirement. |
| `delay` | No | `2500` | Milliseconds to wait for the Facebook pixel before reading its cookies. |
| `cookieDomain` | No | current domain | Domain for the click id cookie. Set this to share a click across subdomains. |
| `cookieExpiry` | No | `30` | Days to keep the click id cookie. |
| `everflow` | No | | Everflow SDK integration; see below. |

### When it creates a click, and when it reuses one

In order, stopping at the first that applies:

1. **A `click_id` is in the page URL.** The visitor arrived through a redirect that
   already created the click. It is reused, not duplicated.
2. **A `_propel_click_id` cookie exists** and the visitor's attribution has not
   changed. The same click is reused — a returning visitor is not a new click.
3. **Otherwise**, a new click record is created.

"Attribution has not changed" means the ad parameters in the URL are the same. A
visitor who comes back through a *different* ad gets a new click, because they are
genuinely new traffic.

### Outbound links

Any anchor carrying `data-propel-link` is rewritten to a tracked redirect, with
the click id attached:

```html
<a href="#" data-propel-link="/offer">See your quote</a>
```

Rewritten anchors are marked `data-propel-resolved="true"`. Links added to the page
later are picked up automatically, so this works with content rendered after load.

The script also injects the click id into forms on the page, so a form submission
carries it to your backend.

### Everflow

If you use Everflow's own SDK alongside PostbackX, pass its ids and both are fired
together:

```javascript
PropelDirect.init({
  trackingId: 'YOUR_CAMPAIGN_TRACKING_ID',
  offerId: 'YOUR_OFFER_ID',
  apiUrl: 'https://propel-lander-api.propelsys.workers.dev',
  everflow: {
    offer_id: 123,
    affiliate_id: 456
  }
})
```

`offer_id` and `affiliate_id` are required when the `everflow` block is present.
`uid`, and `sub1` through `sub4`, are optional overrides.

> The PostbackX click id is passed to Everflow as **`sub5`**. When you configure
> Everflow's postback, its click id macro is therefore `{sub5}` — see
> [postback parameters](/reference/postback).

### What it stores in the browser

| Name | Where | Purpose |
| --- | --- | --- |
| `_propel_click_id` | Cookie and `localStorage` | The current click id. |
| `_propel_attribution_key` | Cookie | Detects when a returning visitor arrived through a different ad. |

## Conversion firing

For when the conversion happens on **your** page rather than the offer's, and no
offer source is going to send a postback for it.

Add this to the thank-you or confirmation page — the page a visitor only reaches
after converting:

```html
<script src="https://propel-lander-api.propelsys.workers.dev/conversion-snippet.js"></script>
<script>
  PropelConvert.fire({
    postbackUrl: 'https://postbacks.postbackx.com',
    payout: 0,
    eventName: 'lead'
  })
</script>
```

| Option | Required | Default | Description |
| --- | --- | --- | --- |
| `postbackUrl` | Yes | | The postback host, **base URL only**. |
| `payout` | No | `0` | Revenue for this conversion. `0` uses the offer's default payout. |
| `eventName` | No | `lead` | Which conversion action fired. |
| `clickId` | No | | Override the click id. Normally omit it and let the script find it. |

> `postbackUrl` takes the host with no path: the script appends `/postback`
> itself. Passing `https://postbacks.postbackx.com/postback` produces a doubled
> path and the conversion is lost.

Left to itself, the script finds the click id in this order: the `clickId` you
passed, then the `_propel_click_id` cookie, then `localStorage`, then a `click_id`
parameter in the page URL.

Because this fires from a browser, treat it as best-effort: a visitor who closes
the tab early never runs it. Where your offer source can send a real
[postback](/reference/postback), prefer that.
