# How to see which tweet made a sale

Source: https://databull.app/guides/which-tweet-made-a-sale
Updated: 2026-10-30 · Author: Ahmed Gagan (maker of DataBull)

> Your analytics says "x.com" or "Direct". You posted ten times this week. Here is why the tweet itself gets lost, and the small habit that keeps it.

**Short answer:** You can't tell from the referrer alone. X sends visitors through t.co, browsers pass on only "https://t.co/", and the X app's in-app browser often passes nothing. To know which tweet sold, give each post its own link with a `utm_campaign` (or `?ref=`), then use analytics that ties the payment to that visit.

## Why the tweet gets lost

Every link in a post on X is wrapped in a `t.co` short link. Each short link is unique, so in theory it identifies the post. In practice that path never reaches you:

- **Browsers trim the referrer.** The default referrer policy in current browsers is `strict-origin-when-cross-origin`: when someone goes from one site to another, only the origin travels. Your analytics sees `https://t.co/`, not `https://t.co/AbC123`. Every tweet looks the same.
- **The app often sends nothing.** Most clicks on X happen in the mobile app, which opens links in its own in-app browser. Visits from in-app browsers frequently arrive with no referrer at all, so most tools file them under Direct.
- **The sale happens later.** Even when you know the visit came from X, the purchase may come days later, on another visit, after a Google search for your name. The Stripe payment itself carries no trace of any of it.

So "x.com sent 300 visitors" is the most a referrer can tell you. To get from there to "the launch thread made $340", you need two things: a link per post, and a way to tie the payment to the visit.

## Step 1: give each post its own link

Add UTM tags to the link before you post it. Keep the first two the same every time and change only the campaign:

```
https://yourapp.com/?utm_source=x&utm_medium=social&utm_campaign=launch-thread
https://yourapp.com/?utm_source=x&utm_medium=social&utm_campaign=pricing-rant
https://yourapp.com/pricing?utm_source=x&utm_medium=social&utm_campaign=pricing-reply
```

A few rules make the report readable later:

- **One campaign name per post**, short and lowercase, with dashes: `launch-thread`, not `Launch Thread (final)`.
- **Same source spelling every time.** `x` and `twitter` and `X.com` become three rows in most tools.
- **Use `utm_content` for variants** of the same post, such as the link in the first tweet vs the last tweet of a thread.
- **Don't tag links to your own site from your own site.** Internal UTMs overwrite the real source of the visit.

Prefer something shorter? `?ref=launch-thread` works in many tools, though it usually fills the source rather than the campaign. Pick one style and stick to it.

> **The habit that sticks:** keep a note with your base link and change one word per post. It takes ten seconds, and after a month you can rank your posts by money instead of likes.

## Step 2: tie the payment to the visit

A tagged link tells you which post brought a visitor. It doesn't tell you which visitor paid. For that, the visitor needs an id that reaches the checkout. With Stripe that means `client_reference_id` on payment links or metadata on Checkout Sessions; [this guide covers each Stripe setup](https://databull.app/guides/track-stripe-revenue-by-traffic-source), and [this one has the code](https://databull.app/guides/utm-tracking-stripe-checkout) to carry UTM tags into Stripe yourself.

Without that link, you are left guessing from timing: a sale arrived an hour after the thread went out, so it was probably the thread. Sometimes true, often not.

## Step 3: read the result per post

Once each payment carries its visit, you can rank campaigns by revenue instead of clicks. Two things are worth looking at:

| Question | What to look at |
| --- | --- |
| Which post made the most money? | Revenue by campaign, filtered to source x.com. |
| Did the post find buyers, or close them? | First source vs the source credited with the sale. X often finds people who buy later from a Google search. |
| Are X buyers worth keeping? | Lifetime value by first source, renewals included. |

## The same trick for LinkedIn, Reddit and Threads

The problem is the same everywhere: link shorteners (`lnkd.in`), redirect pages (`out.reddit.com`) and in-app browsers strip or blur the referrer. The fix is the same too. Use `utm_source=linkedin`, `reddit` or `threads`, `utm_medium=social`, and one campaign per post. On Reddit, where links in comments are common, a campaign per thread is usually enough.

## How DataBull does it

DataBull handles both halves for you. The tracking script records the source, referrer and UTM tags of each visit, and names the app when a visit comes from an in-app browser that identifies itself (X, Instagram, Reddit, LinkedIn, TikTok and others), so fewer X clicks end up as Direct. A `?ref=` or `?via=` parameter is read as the source, and `utm_source=x` or `twitter` is grouped with x.com.

On the payment side, the script tags Stripe, Polar, Dodo and Creem payment links with the visitor's id automatically, and server-created checkouts pass two metadata fields. Each sale is then credited to a visit (last non-direct by default, or first or last touch), and you see:

- **Revenue by campaign**, next to visitors, on the dashboard.
- **A Telegram message for every sale** naming its source, channel and campaign, where the buyer landed and when they first visited. [How sale alerts work](https://databull.app/stripe-sale-notifications-telegram).
- **Path to purchase**: the source that first brought each customer next to the one credited with the sale, and how many days and visits it took. [Details](https://databull.app/docs/path-to-purchase).

You can also ask your AI agent directly. With DataBull's MCP server connected, "which X campaign made the most money this month?" is one question in [Claude Code](https://databull.app/mcp/claude-code) or [Cursor](https://databull.app/mcp/cursor).

Checked in October 2026 against: [MDN: Referrer-Policy (default strict-origin-when-cross-origin)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy), [Stripe: Payment Links URL parameters](https://docs.stripe.com/payment-links/url-parameters).

## FAQ

### Can I find the tweet from the t.co link in my analytics?

Usually not. Browsers send only the origin (`https://t.co/`) to other sites by default, so the unique short link is dropped. Visits from the X app often carry no referrer at all. A UTM tag on the link is the reliable way.

### How long after a post should I expect sales from it?

It varies a lot, which is why the payment has to be tied to the visit rather than guessed from timing. Path-to-purchase reports show how many days and visits your buyers usually take, so you know how long to wait before judging a post.

### Should I use utm_campaign or ?ref= for each post?

UTM tags are understood by almost every analytics tool and keep source and campaign separate. `?ref=` is shorter but usually becomes the source. If you want one row per post under X, use `utm_source=x` and a campaign per post.

### What about tweets that send people to my profile or bio link?

The bio link is one link for every post, so it can't tell posts apart. Tag it once (for example `utm_campaign=bio`) so it at least shows up as its own row.
