How to Track ig.me and m.me Link Referrals via API

Attribute Instagram and Messenger DM conversations to campaigns with ig.me/m.me ref parameters — referral webhooks, chat metadata, and replying before the first message.

https://ig.me/m/<username> (Instagram) and https://m.me/<page_username> (Facebook Messenger) deep-link a user straight into a DM thread with your business. Add a ref parameter and the link becomes trackable:

https://ig.me/m/your_username?ref=summer_promo
https://m.me/your_page?ref=qr-store-berlin

ref takes up to 2,083 characters of alphanumerics plus -, _, and = — enough to encode a campaign, a source, and a variant. Put a different ref on your bio link, each ad, each QR code, and every conversation tells you where it came from.

What Postproxy does with a referral

When a user enters the thread via such a link, Meta sends a referral event and Postproxy:

  1. finds or creates the chat for that participant,
  2. stores the referral on the chat — metadata.referral holds { "ref", "source", "type", "received_at" } (latest referral wins) and metadata.last_referral_at is updated,
  3. opens the 24-hour messaging window — per Meta policy a referral lets you reply free-form before the user sends anything,
  4. fires a referral.received webhook.

The referral is captured whether it arrives standalone (user opened the thread and hasn’t typed yet), embedded in the user’s first message, or inside an ice-breaker tap.

One Instagram-specific prerequisite: Meta only sends ig.me referrals for profiles that have at least one ice breaker set. No ice breakers, no referral events — so set them up first. m.me referrals on Facebook have no such requirement.

Handle the webhook

app.post("/webhooks/postproxy", async (req, res) => {
res.sendStatus(200); // ack fast, work after
const event = req.body;
if (event.type !== "referral.received") return;
const { chat, ref, source } = event.data.object;
// attribute the conversation
await crm.tagConversation(chat.id, { campaign: ref, source });
// the referral opened the 24h window — greet before they even type
await fetch(`https://api.postproxy.dev/api/chats/${chat.id}/messages`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POSTPROXY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
body: "Hey! Saw you came from the summer promo — want the discount code?",
}),
});
});

The payload carries the full chat object, the ref, Meta’s source (e.g. SHORTLINK), and type (e.g. OPEN_THREAD) — see the referral.received payload reference.

Greeting on every referral can feel aggressive for some audiences; the conservative variant is to store the attribution on the webhook and only use it when the user’s first message.received arrives.

Read attribution later

No webhook archaeology needed — the latest referral lives on the chat itself:

Terminal window
curl "https://api.postproxy.dev/api/chats/CHAT_ID" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"id": "chat_xyz789",
"platform": "instagram",
"metadata": {
"referral": {
"ref": "summer_promo",
"source": "SHORTLINK",
"type": "OPEN_THREAD",
"received_at": "2026-06-10T12:00:00Z"
},
"last_referral_at": "2026-06-10T12:00:00Z"
}
}

If the same user later enters through a different link, the new referral overwrites metadata.referral — keep webhook events if you need the full history.

Rules and limits, in one place

RuleValue
PlatformsInstagram (ig.me), Facebook Messenger (m.me)
Instagram prerequisiteAt least one ice breaker set on the profile
ref format≤ 2,083 chars; alphanumerics, -, _, =
Stored atchat.metadata.referral (latest wins)
Webhookreferral.received
Opens 24-hour windowYes — reply before the first message
Arrival formsStandalone, first message, ice-breaker tap

Full details: ig.me / m.me link referrals in the Direct Messages reference. For the sending side of the conversation, see How to Send Instagram DMs via API and How to Send Facebook Messenger Messages via API.

Ready to get started?

Start with our free plan and scale as your needs grow. No credit card required.