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

# Connect Keitaro to OnlyFans API Smart Links (/introduction/guides/keitaro-smart-links)

import { Step, Steps } from "fumadocs-ui/components/steps";

## What the Keitaro integration does

Keitaro is a self-hosted traffic tracker and redirect platform used by media buyers. This integration connects Keitaro to OnlyFans API **Smart Links** so that every new subscriber you generate is reported straight back to Keitaro for attribution.

There are two halves: getting Keitaro's click ID into your Smart Link, then sending the conversion back to Keitaro when a subscription happens. Because Keitaro isn't a built-in Ad Platform, you wire it up with a Smart Links **Postback** (a plain GET request) rather than a paste-a-token connector.

<Callout>
  **What you'll need**

  * An active OnlyFans API account with **Smart Links** enabled
  * A **Smart Link** created for the creator you're promoting
  * A **Keitaro campaign** with an offer, plus your Keitaro **postback URL** (its domain and key)
</Callout>

## How the pieces connect

Keitaro's `{subid}` (its click ID) is passed into your Smart Link as `?ecid={subid}`, where it's saved as your external click ID. When a fan subscribes, the postback sends that value back to Keitaro as `{external_click_id}`, which Keitaro matches to the original click. The subscription amount flows the same way: OnlyFans API's `{amount_gross}` becomes Keitaro's `payout`.

<Callout type="warn">
  The full chain must be **ad → Keitaro campaign URL → Smart Link**, with nothing in between. Two setups that silently break tracking:

  * **A link-in-bio page between Keitaro and the Smart Link** (Linktree and similar). Bio pages don't forward the click ID, so every conversion reaches Keitaro with an empty `subid` and is dropped.
  * **Ads pointing directly at the Smart Link.** If the ad's destination is your `trk.of-traffic.com` link instead of the Keitaro campaign URL, Keitaro never sees the click, so it can never attribute the conversion, no matter how the postback is configured.
</Callout>

## Step-by-step setup

<Steps>
  <Step>
    ### Point Keitaro's offer URL at your Smart Link

    In your Keitaro campaign, set the **offer URL** to your Smart Link with `?ecid={subid}` on the end:

    ```text
    https://trk.of-traffic.com/go/YOUR_SMART_LINK_ID?ecid={subid}
    ```

    Replace `YOUR_SMART_LINK_ID` with the ID from your Smart Links dashboard. `{subid}` is Keitaro's macro for the click ID: Keitaro swaps it for the real click ID when it redirects the visitor, and the Smart Link reads it from the `ecid` parameter and saves it.

    <Callout type="warn">
      This has to be the **offer URL set inside Keitaro** so Keitaro performs the `{subid}` substitution, not a raw link posted straight to your traffic source. Pasting the link with `{subid}` anywhere else (a bio page button, an ad's URL field) sends the literal text `{subid}` as the click ID, which Keitaro can never match.
    </Callout>
  </Step>

  <Step>
    ### Create the postback in OnlyFans API

    Log into your [OnlyFans API Dashboard](https://app.onlyfansapi.com), open **Smart Links → Postbacks**, and create a new postback with these settings:

    * **HTTP method:** GET
    * **Conversion type:** `new_subscriber`
    * **Scope:** Global (or Campaign-specific with this Smart Link attached)
    * **URL:**

    ```text
    https://YOUR_KEITARO_DOMAIN/YOUR_POSTBACK_KEY/postback?subid={external_click_id}&status=sale&payout={amount_gross}
    ```

    A quick note on each value:

    * `{external_click_id}` outputs the Keitaro click ID captured in Step 1. This is what lets Keitaro match the conversion to the original click.
    * `status=sale` because a paid subscription is a confirmed sale. If this link is a free trial with no payment, use `status=lead` instead.
    * `{amount_gross}` is the subscription amount. Free-trial links send `0.00` here, which is expected.

    Keep the `YOUR_KEITARO_DOMAIN` and `YOUR_POSTBACK_KEY` parts exactly as they appear in your own Keitaro postback URL, those are yours from Keitaro.

    <Callout type="info">
      A Global postback also fires for Smart Links whose traffic doesn't come through Keitaro; those requests carry an empty `subid` and Keitaro rejects them, which is harmless but fills its **Maintenance → Logs → Received postbacks** log. If you use Campaign-specific scope instead, remember to attach every new Smart Link you create, including replacements when you rotate links, or conversions on the new link silently stop reaching Keitaro.
    </Callout>

    <Callout type="warn">
      Don't use `status=subscription`, Keitaro doesn't recognize that value. Use `status=sale` for a paid subscription or `status=lead` for a free trial.
    </Callout>
  </Step>

  <Step>
    ### Test it with a single click

    You don't need to wait for a real subscription to verify the click ID capture:

    1. Open your Keitaro **campaign URL** in a browser. You should land on OnlyFans via the Smart Link redirect.
    2. In Keitaro, open **Reports → Clicks log** and note the new click's **Subid**.
    3. In your Smart Link's **Clicks report**, the **External Click ID** column for that click should show the same value.

    If the values match, attribution is wired correctly. After the first real subscription you'll see a `new_subscriber` row in the **Conversions report** with the External Click ID next to it, and the conversion will appear in your Keitaro dashboard.

    <Callout>
      If the **External Click ID** column is empty in the Clicks report, the issue is Step 1 (Keitaro isn't passing the click ID in). Fix that first, no postback settings can work without it.
    </Callout>
  </Step>
</Steps>

## Keitaro ↔ OnlyFans API variables

| Keitaro                     | OnlyFans API                  | Notes                                                        |
| --------------------------- | ----------------------------- | ------------------------------------------------------------ |
| `{subid}` macro (offer URL) | passed in via `?ecid={subid}` | Keitaro replaces it with the click ID at redirect            |
| `subid` postback param      | `{external_click_id}`         | Matches the conversion back to the original click            |
| `payout` postback param     | `{amount_gross}`              | Gross subscription amount; `0.00` for free trials            |
| `status` postback param     | static `sale` / `lead`        | `sale` = paid sub, `lead` = free trial; never `subscription` |

<Callout type="info">
  For the full list of postback variables (net vs gross amounts, fan and creator info, transaction details) and every available conversion type, see the [Smart Links guide](/introduction/guides/onlyfans-meta-pixel-smart-links#available-postback-variables).
</Callout>

## Troubleshooting

| Problem                                                        | Fix                                                                                                                                                                                                                                        |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **External Click ID** column is empty in the Clicks report     | Keitaro isn't passing the click ID. Make sure `?ecid={subid}` is on the **offer URL inside Keitaro** (not a raw link at your traffic source), and that no bio page sits between Keitaro and the Smart Link.                                |
| **External Click ID** shows the literal text `{subid}`         | The macro was pasted somewhere Keitaro doesn't control, usually a bio page button or the ad's URL field. Only the offer URL field inside Keitaro expands `{subid}`.                                                                        |
| Conversion shows in OnlyFans API but not in Keitaro            | Check the postback URL's domain and key match your Keitaro postback exactly, and that `subid={external_click_id}` is present. Keitaro's **Maintenance → Logs → Received postbacks** shows every request it got and the `subid` it carried. |
| Re-subscribed with the same fan account to test, nothing fired | The `new_subscriber` postback fires **once per fan per Smart Link**. Test with a fan account that has never subscribed through that link.                                                                                                  |
| Subscription came long after the click                         | Conversions are attributed when the subscription happens within **6 hours** of the click.                                                                                                                                                  |
| Keitaro ignores or rejects the conversion status               | Use `status=sale` (paid) or `status=lead` (free trial). `status=subscription` is not recognized by Keitaro.                                                                                                                                |
| `payout` shows `0.00`                                          | Expected for free-trial links (no payment). Paid subscriptions send the gross amount via `{amount_gross}`.                                                                                                                                 |