Instagram Link Tracking: Bio, Stories, DMs, Ads and QR
Part of the Social media handbook
Track every Instagram link: five bio slots, Story stickers, DMs, ads, creators and print. Plus how to target an Instagram campaign, when to post, why GA4 calls Instagram traffic Direct, and a campaign checklist.
Instagram never tells you who clicked your link. What you can get is a count per placement (each bio link, each Story, each DM reply, each creator) with the time, country and device behind every click. Instagram link tracking that works gives every placement its own short link, set up before you post, with UTM parameters on the destination if you use Google Analytics.
This guide is the Instagram part of the social media link tracking handbook. It covers where Instagram lets you link, the tracking setup for each placement, how to target and time a campaign, and how to read the clicks. Stories have their own guide: tracking Instagram Story link sticker clicks.
What Instagram shows you, and what it doesn't
Instagram's insights are free for professional (creator and business) accounts; switching a public account to professional costs nothing. For links, the useful parts are:
| Insight | What it counts | Where |
|---|---|---|
| Story Interactions | Replies, shares, sticker taps and link taps | Open the Story, then Activity > Insights |
| Story Profile activity | Profile visits, follows and website clicks from the Story | Same screen |
| Account Total followers | Top locations, age range and the times followers are most active (from 100 followers) | Insights from your profile |
What insights don't give you:
- Who tapped. No names, no list of accounts.
- What happened next. A tap is counted inside the app. Whether the page loaded, and whether anyone bought, happens outside it.
- A per-link split of your bio. Instagram's help pages don't describe one for the five bio links, and we couldn't confirm one in the app.
- DMs, creators' posts and print. A link you paste into a DM, a link a creator posts, and a QR code on a poster are invisible to your insights.
A short link per placement fills those gaps. It counts each click when it reaches snu.to, so it measures arrivals rather than taps, and it works wherever the link is posted. It doesn't identify anyone either: SendURL records country, never city, and no account details.
Where you can link on Instagram in 2026
| Placement | Clickable? | Tracking setup |
|---|---|---|
| Bio | Yes, up to 5 links (Help Centre) | One short link per slot |
| Story | Yes, link sticker, all accounts since 27 Oct 2021 except new accounts and repeat rule-breakers (Instagram) | One short link per Story frame |
| Highlights | Yes, the Story's sticker goes with it; Highlights stay on your profile "until you remove them" (Instagram) | Same link as the Story; consider an expiry |
| Direct messages | Yes, opens in the in-app browser (Help Centre) | One link for DM replies |
| Feed post and Reel captions | No, on most accounts | Meta One Advanced, from $49.99 a month, lists "links in organic posts and reels" (Meta, 15 Sep 2026) |
| Reels product links | Catalogue products only: up to 30 per Reel, in the countries Meta lists (Instagram, 24 Mar 2026) | Meta's shopping reports, not a short link |
| Ads | Yes, the action button | Tagged destination URL, no short link (see ads) |
| Through a QR code | One short link per printed piece |
Two consequences. First, "link in bio" now means up to five links, so you can give a campaign its own slot without losing your evergreen link. Second, posting a short link in a caption does almost nothing: it isn't tappable, and the post should point to the bio or a Story instead.
One short link per placement
All of these point at the same destination, https://example.com/autumn-sale, tagged differently:
| Placement | Slug | utm_content | What you learn |
|---|---|---|---|
| Bio slot 1 (evergreen shop link) | shop-ig-bio1 | bio-link-1 | Baseline traffic from the profile |
| Bio slot 2 (campaign) | autumn26-ig-bio2 | bio-link-2 | Whether the campaign moved profile visitors |
| Story, 14 Oct, frame A | autumn26-st-1014a | story-1014-a | Clicks per Story frame, by hour |
| DM replies | autumn26-ig-dm | dm-reply | How many people you answered actually went |
| Creator Maya | autumn26-cr-maya | creator-maya | Each creator's clicks without asking for screenshots |
| Creator Leo | autumn26-cr-leo | creator-leo | Same, for comparison |
| Shop window poster | autumn26-poster | window | Scans of the printed QR code |
Create them in the SendURL console (the form proposes a random 6-character slug, or you type your own), or from a sheet with the script in the social media hub. Slugs are case-sensitive, unique across snu.to and permanent, so use the campaign prefix and lowercase. How to name a custom short link has the rules.
The bio slot needs one more decision. If slot 2 rotates from campaign to campaign, either replace the link in Instagram with the new campaign's short link (clean history per campaign), or keep one short link in the slot and change where it points. SendURL changes a destination through the API only (PATCH /links/:id with a new destinationUrl), and the click history then spans every campaign the link served.
Posting the same video as a Reel and on TikTok? Give each profile its own link. On TikTok there is one bio link and no per-video count; how to track TikTok bio link clicks matches click times to posts to estimate which video sent them.
UTM parameters for Instagram
If you use GA4, tag every destination. These values land where you expect under Google's default channel rules, checked 15 October 2026:
| Placement | utm_source | utm_medium | utm_content | GA4 channel |
|---|---|---|---|---|
| Bio | instagram | social | bio-link-2 | Organic Social |
| Story | instagram | social | story-1014-a | Organic Social |
| DM | instagram | social | dm-reply | Organic Social |
| Creator post | instagram | social | creator-maya | Organic Social |
| Ads | {{site_source_name}} | paid-social | {{ad.name}} | Paid Social |
utm_campaign is the same everywhere, for example 2026-10-autumn-sale. Values that cause trouble:
utm_source=insta,ig_bioorinstagram_story: not on Google's social source list. Withutm_medium=socialthe visit still lands in Organic Social; with a made-up medium such asstoryorbio, it lands in Unassigned.Instagramandinstagramin different links: GA4's channel rules ignore case, but its reports don't, so you get two rows (Google).- UTMs on the short link:
snu.to/autumn26-ig-bio2?utm_source=instagramdoesn't work, because SendURL doesn't pass on a query added to the short URL. Tag the destination, then shorten it.
A tagged destination looks like this:
https://example.com/autumn-sale?utm_source=instagram&utm_medium=social&utm_campaign=2026-10-autumn-sale&utm_content=bio-link-2Why Instagram traffic shows as Direct in GA4
Instagram opens links in its in-app browser by default, "when you tap a link in a post, ad, Story or message" (Help Centre). Outbound links pass through Meta's link shim, which exists to tell the destination the visit came from Meta while hiding the address of the page it came from (Meta Engineering, 2012). When a referrer survives, it is usually the shim's host, l.instagram.com, which is on Google's social source list, and the visit counts as Organic Social. When no referrer arrives, GA4 has nothing to go on and files the session as Direct.
UTMs settle it, because they travel in the URL rather than in a header. For the clicks themselves, the short link doesn't need a referrer: each placement has its own link. SendURL also records the app when it identifies itself, so a click opened inside Instagram shows browser: "Instagram" with browserType: "inapp" in its click record. A click on your bio link that opened in Chrome or Safari came from Instagram on the web, or from a copy of the link shared somewhere else.
Target an Instagram campaign
Targeting starts with who clicks, not who follows. Three sources, from free to paid:
1. Instagram's own audience insights. The account's Total followers insight shows top locations, age range and the times followers are most active, once you have 100 followers. That is who could see an organic post.
2. Your click data. After the first week, compare the country and device of the clicks on each placement. Followers are where your audience lives; clicks are where your buyers are likely to be. For example, if a creator's link draws most of its clicks from one country you don't ship to, that creator is reaching the wrong market, however big their audience. SendURL gives country from the IP address (no city, and VPNs move it), so treat it as a strong hint rather than an address.
3. Paid targeting in Meta Ads Manager. Meta's Advantage+ audience lets Meta's AI find the audience instead of you defining it. You can still set audience controls, which are hard limits: locations, minimum age, custom audiences to exclude, and languages. Age, gender, detailed targeting and custom audiences can be added as suggestions, which Meta may go beyond "when it's likely to improve performance" (Meta Business Help Centre). A custom audience can be built from people who engaged with your Instagram account (Meta for Developers).
A practical order: post organically first, read a week of clicks by country, then set the ad's location controls to the countries where clicks came from and use the engaged-audience custom audience as a suggestion. Meta doesn't recommend Advantage+ audience for retargeting, so retarget with a regular audience.
Ads: use the tagged URL, not a short link
For Instagram ads, put the full tagged destination in the ad's website URL, not a snu.to link. Two reasons:
- Meta adds to the URL. Dynamic parameters such as
{{campaign.name}}and{{placement}}are filled in at click time, and Meta attaches its click ID,fbclid, to the URL "when a user clicks an ad on Facebook and/or Instagram" (Meta for Developers). On a short link, SendURL would drop all of it, because it doesn't pass on a query added to the short URL. Your site, its pixel and GA4 would lose them. - Ads Manager counts the clicks already. A short link would duplicate a number you have, and lose the parameters above.
Meta's parameter list includes {{campaign.name}}, {{adset.name}}, {{ad.name}}, {{placement}} (for example instagram_feed, instagram_stories) and {{site_source_name}}, which is ig for Instagram and fb for Facebook (Meta Business Help Centre). In the ad's URL parameters field:
utm_source={{site_source_name}}&utm_medium=paid-social&utm_campaign=2026-10-autumn-sale&utm_content={{ad.name}}&placement={{placement}}ig and fb are both on Google's social list, so with paid-social these visits land in Paid Social. Messenger (msg) and Audience Network (an) are not on the list and would land in Paid Other. Name-based parameters keep the name the ad had when it was first published, so name ads in lowercase with hyphens before you publish. A typed utm_campaign (as above) avoids the spaces a campaign name brings (%20 in the URL).
Use a short link in an ad only where people will type or scan it: a URL shown in the video, or a QR code in the creative.
When to post: what the studies measure
Every published "best time to post on Instagram" study measures engagement (likes, comments, shares, saves), and they don't agree:
| Study | Published | Data | Metric | Instagram answer |
|---|---|---|---|---|
| Sprout Social | 31 Mar 2026 | ~2 billion engagements, ~307,000 profiles, 27 Nov 2025 to 27 Feb 2026 | Engagements including clicks, local time | Mon 2 to 4pm, Tue 1 to 7pm, Wed 12 to 9pm, Thu 12 to 2pm |
| Buffer | Sep 2026 | 9.6 million Instagram posts, Jan 2024 to Dec 2025 | Median engagement rate | Thu 9am, Wed 12pm, Wed 6pm |
| Hootsuite | 19 Nov 2025 | 1 million+ posts across networks | Engagement, "time-zone agnostic" | Mon 3 to 9pm, Tue 5 to 8am and 3 to 7pm, Thu 5 to 7pm |
| Later | 21 Apr 2026 | 6 million+ feed posts, Jan to Oct 2024 | Engagement rate, audience local time | 5am |
Sprout's engagement count includes link clicks among reactions, comments, shares and messages; none of the four reports link clicks on their own. A like and a click are different decisions, made at different moments, so treat these windows as a starting point for a test, not an answer.
Your own data is better on both counts. Instagram's Total followers insight shows when your followers are active. Your short links show when people actually click, and how long each placement keeps earning: a Story's clicks come in a burst and stop when it expires after 24 hours, while a bio link collects for weeks. Post the same kind of Story at two different times, each with its own link, and compare clicks in the first 24 hours. Find your best time to post from link clicks builds a weekday-by-hour heatmap from the timestamps.
Track a campaign end to end
A plan for a two-week Instagram campaign, from setup to read-out:
- A week before. List every placement in the tracking sheet: bio slot, each planned Story, DM replies, each creator, each ad, each printed piece. Decide the reading day.
- Create the links. One per row, tagged destination, campaign-prefixed slug. Add an expiry to links for an offer that ends; a Story in Highlights keeps its link working after the sale is over.
- Brief the creators. Send each one their own short link,
snu.to/autumn26-cr-maya, for their Story sticker or bio. You'll see their clicks without access to their account or screenshots of their insights. A creator-specific promo code is a useful cross-check: clicks show interest, codes show sales. - Set up the ads with the tagged URL and Meta's dynamic parameters, as above.
- Print. Each printed piece gets its own link's QR code (SVG from the console). Scans are flagged
source: "qr", so the poster stays separate from everything else. A QR code can also point a short link at your Instagram profile, which counts how many people the poster sent to Instagram. - Launch day. Open each short link once on a phone to check it lands; note that each test is a click.
- Read on the chosen day. Clicks per placement per day live, previews discounted, device and country per placement, GA4 sessions by
utm_content. - Act. Keep the placements that earned clicks, drop or change the rest, and move the ad's location controls toward the countries where clicks came from.
SendURL sees the click, not the sale. Revenue per placement needs your shop's or GA4's conversion data, joined on utm_content or the promo code.
Reading the clicks
The console's link page shows total clicks, the last 7 days and a daily chart, and each click in the Recent clicks list opens its full record. For the shape of a placement over its first two days, this script buckets one link's clicks by hours since posting and shows which app they opened in. It needs the link's id (also in its console address, console.sendurl.to/links/<id>) and the time you posted (install requests first with pip install requests):
import os, time
from collections import Counter
from datetime import datetime
import requests
API = "https://api.sendurl.to/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['SENDURL_API_KEY']}"}
POSTED = datetime.fromisoformat(os.environ["POSTED_AT"].replace("Z", "+00:00"))
def clicks(link_id):
"""Every click of one link, newest first, 10 per request."""
params = {"limit": 10}
while True:
r = requests.get(f"{API}/links/{link_id}/clicks", headers=HEADERS, params=params, timeout=10)
r.raise_for_status()
page = r.json()
yield from page["clicks"]
if not page["pagination"]["hasMore"]:
return
params["cursor"] = page["pagination"]["nextCursor"]
time.sleep(0.25) # stay under the API's rate limit
by_hour, apps, previews = Counter(), Counter(), 0
for c in clicks(os.environ["LINK_ID"]):
if "facebookexternalhit" in (c["userAgent"] or ""):
previews += 1 # Meta's preview fetcher, not a person
continue
at = datetime.fromisoformat(c["clickedAt"].replace("Z", "+00:00"))
by_hour[max(-1, min(int((at - POSTED).total_seconds() // 3600), 48))] += 1
apps[c["browser"] if c["browserType"] == "inapp" else "other browser"] += 1
for hour in sorted(by_hour):
label = "before" if hour < 0 else "48h+" if hour == 48 else f"{hour}h"
print(f"{label:>6} {'#' * by_hour[hour]} {by_hour[hour]}")
print("opened in:", dict(apps), "| previews skipped:", previews)Run it with LINK_ID=<id> POSTED_AT=2026-10-14T17:30:00Z python3 clicks_after_posting.py. Clicks "before" posting are your own tests. Run it for two Stories posted at different times and you have the timing test above; run it for each creator and you see whose audience clicks fast and whose keeps clicking.
Free lists 7 days of analytics history and Pro 30; the link page and the API cover every click. What a click record contains explains each field, and can you see who clicked your link covers what the data can't tell you.
Checklist
- Bio: a campaign slot (of five) with its own short link; the evergreen link left in slot 1
- One short link per Story frame, DM reply, creator and printed piece, all with the campaign prefix
- Destinations tagged
utm_source=instagram&utm_medium=social,utm_contentnaming the placement - Ads: the tagged URL with Meta's dynamic parameters, no short link
- No short links in captions, where they aren't clickable
- Expiry set on offer links that may live on in Highlights
- Location and device of first-week clicks checked before ad targeting is set
- Posting times noted for each Story and post, so clicks can be read by hours since posting
- Reading day fixed; previews (
facebookexternalhit) and your own test clicks discounted
Naming template for the sheet:
slug: <campaign>-ig-bio<slot> | <campaign>-st-<mmdd><frame> | <campaign>-ig-dm | <campaign>-cr-<handle> | <campaign>-poster
utm_source: instagram (ads: {{site_source_name}})
utm_medium: social (ads: paid-social)
utm_campaign: <yyyy>-<mm>-<offer> e.g. 2026-10-autumn-sale
utm_content: bio-link-<slot> | story-<mmdd>-<frame> | dm-reply | creator-<handle> | windowStart with the bio link: shorten it on the SendURL home page and watch the first clicks arrive.
Frequently asked questions
Can you see who clicked your Instagram link?
No. Instagram's insights count link taps without naming anyone, and a link tracker sees the request, not the person. What you can see is how many clicks each link got, when, and the country, device and app behind each one.
How do I see link clicks on Instagram?
Open the Story's insights: link taps are counted under Interactions, and website clicks under Profile activity. Insights are free on professional (creator and business) accounts. For clicks that reached your site, per bio slot, DM or creator, use a separate short link in each place and read its click count.
Why does Instagram traffic show as direct in Google Analytics?
Links open in Instagram's in-app browser, and the visit often arrives without a referrer. With nothing to go on, GA4 files the session as Direct. Add utm_source=instagram and utm_medium=social to the destination URL and the visit lands in Organic Social.
How many links can you have in your Instagram bio?
Up to five. Add them under Edit profile, then Links, then Add external link. Instagram's Help Centre says anyone, on or off Instagram, can see them.
Can you put a link in an Instagram caption?
You can type one, but on most accounts it isn't clickable. Meta's paid Meta One Advanced plan, announced in September 2026, lists links in organic posts and Reels among its features, with availability varying by region and account.
Start tracking links free.
Create your first short link with click analytics in seconds. No credit card, no sign-up to start.
Shorten a link