Guide · X (Twitter)

How to see which tweet made a sale

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.

By Ahmed Gagan, maker of DataBull · Published · 4 min read

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:

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:

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, and this one has the code 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:

QuestionWhat 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:

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 or Cursor.

Checked in October 2026 against: MDN: Referrer-Policy (default strict-origin-when-cross-origin), Stripe: Payment Links URL parameters. Spotted something out of date? Tell us.

Questions

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.

Find out which of your posts pay the bills.

One script, one payment connection, and you'll know by tomorrow.