6 min read
App Store campaign links: ct, pt and naming per channel
How to build App Store campaign links with the pt and ct parameters, name one per newsletter, X post, blog post and podcast, and what the results can't tell you.
App Store campaign links are ordinary links to your product page with two extra query parameters: a provider token that identifies your developer account and a campaign token that you choose. Tap one, and the downloads that follow are counted under that campaign in App Store Connect. They are Apple's own way to see which newsletter, post or podcast mention sent people to the App Store, so it pays to set them up carefully once.
What follows is the setup in order: the anatomy of the link, a naming scheme, one link per channel, and what the results can and can't tell you.
What does an App Store campaign link look like?
https://apps.apple.com/app/apple-store/id1234567890?pt=123456&ct=newsletter-2026-07&mt=8
The parts:
id1234567890is your app's Apple ID, the number in your App Store URL.ptis your provider token. It identifies your developer account, not the campaign, so it is the same on every link you make. App Store Connect includes it when you generate a campaign link in its analytics section, and you can copy it from any link generated there.ctis the campaign token. This is your label, and the one part you'll change per link. Apple caps it at 40 characters.mt=8marks the link as pointing to an app. Apple's generator adds it; keep it.
Your UTM parameters mean nothing here. App Store Connect reports on ct, not on utm_campaign.
How should you name campaign tokens?
The token is free text, which means a year from now you will have launch, Launch2, nl_nov and newsletter-november all describing the same thing. Pick a scheme before your first link and write it down.
A scheme that holds up:
- Channel first.
newsletter,x,blog,podcast,site. Sorting by token then groups by channel for free. - Then the specific placement. The issue, the post slug, the episode.
- Lowercase, hyphens, no spaces. Spaces get encoded, capitals get mistyped.
- Dates as
2026-07when you need them, so they sort. - No personal data. The token is visible to anyone who sees the link.
The 40-character cap is the real constraint. blog-how-we-handle-offline-sync-in-swiftui is already over it. Shorten the slug rather than dropping the channel prefix.
If you also use UTM parameters on the web, reuse the same words: utm_campaign=offline-sync on the blog post, ct=blog-offline-sync on its App Store button. You can't join the two datasets per person, but you can at least put them side by side without a lookup table. We go deeper on the web half in UTM parameters naming convention.
How do you build one link per channel?
The principle is one token per place a link can appear, and nothing shared between places. If the same link sits in your newsletter and your X bio, you'll never separate them again.
| Channel | Example ct | Granularity |
|---|---|---|
| Newsletter | newsletter-2026-07 | One per issue |
| X | x-bio, x-2026-07-launch | One for the bio, one per thread you care about |
| Blog | blog-offline-sync, blog-footer | One per post that links to the App Store, one for site-wide buttons |
| Podcast | podcast-showname-ep12 | One per episode or appearance |
| Your website | site-hero, site-pricing | One per button position |
Newsletter
Make a new token per issue. Issues go out on a date and get most of their clicks in the first days, so per-issue tokens give you a clean comparison between issues. If you have a permanent "get the app" link in the footer, give that its own token, separate from the link in the body.
X
Your bio link is evergreen; tag it once as x-bio. For posts, tag the ones that are meant to drive downloads, such as a launch thread or a feature announcement. Tagging every post produces tokens with a download or two each, which privacy thresholds will mostly hide anyway.
Blog
Each post that has an App Store button gets its own token, named after the post. Site-wide placements, like a header button or a footer badge, share one token per position. This is where the web side helps: your analytics already knows how many people read each post, so you can compare readers per post with downloads per post.
Podcast
Nobody types a 90-character URL they heard in their earbuds. Set up a short path on your own domain, something like yourapp.com/pod, that redirects to the campaign link. Say the short path on air, put the full link in the show notes, and use a different short path per show if you appear on several. A side benefit: your server logs count the redirects, so you see the taps even on days when Apple's numbers are too small to show.
Where do campaign results show up?
App Store Connect's analytics lets you view results per campaign. The downloadable analytics reports are more precise about the structure: in the detailed variants, each row is a day, a source type and a campaign, with counts for that combination.
That structure has a consequence. A campaign isn't a source type of its own; it is reported under whichever source the tap came through. The same token can appear under more than one source, for example when some readers open your newsletter in a browser and others in a mail app. To get the total for a campaign, sum it across sources. If the source types themselves are new to you, App Store Connect source types explains each one.
What can't campaign links tell you?
Quite a lot, and it's better to know before you build a plan on them.
They are aggregate. You get counts per campaign per day, never a list of who downloaded. Your app doesn't receive the token, so you can't attach it to a user, a trial or a subscription. There is no per-user campaign link.
They only count what they touch. Someone who hears your podcast mention and searches for your app by name shows up in App Store Search with no campaign. For spoken and offline channels, the campaign link captures a part of the effect, never all of it.
Small numbers get withheld. Apple's privacy thresholds hide low counts, and a small campaign split by day and source is exactly where they bite. Judge campaigns over a week or a month.
Reports are a day or two late. The day after a send, the numbers are still filling in.
Links break quietly. Some link shorteners, rewriting tools and copy-paste mishaps drop the query string. Before a big send, tap the final link on a phone and check that ct survived.
Because the data is aggregate, the honest way to connect campaigns to money is by period: downloads per campaign this week next to trials and new MRR in the following week, shifted by your trial length. It shows direction and size, not cause.
Joinsight has a campaign link builder that fills in your provider token and enforces the 40-character limit, and its App Store Connect integration shows downloads by campaign within each source next to RevenueCat trials and new MRR, with thin data labeled.