URL Shortener With UTM Tracking โ The Developer's Campaign Analytics Setup
Combining a URL shortener with UTM parameters gives you clean shareable links with full campaign attribution in Google Analytics.
As a developer, you probably hand URLs to clients, share links in documentation, and build features that involve shareable links. Adding UTM parameters and URL shortening to this workflow gives you click data you didn't have before, with minimal extra effort.
What UTM parameters are
UTM parameters are query string keys that analytics tools (Google Analytics, Plausible, and others) use to attribute traffic sources. The standard ones:
utm_sourceโ Where the traffic comes from (email, twitter, slack)utm_mediumโ The channel (newsletter, social, referral)utm_campaignโ The specific campaign nameutm_contentโ Differentiates similar links in the same campaign
Building UTM links in code
function buildUtmUrl(baseUrl, params) {
const url = new URL(baseUrl);
if (params.source) url.searchParams.set("utm_source", params.source);
if (params.medium) url.searchParams.set("utm_medium", params.medium);
if (params.campaign) url.searchParams.set("utm_campaign", params.campaign);
if (params.content) url.searchParams.set("utm_content", params.content);
return url.toString();
}
const link = buildUtmUrl("https://myapp.com/pricing", {
source: "email",
medium: "newsletter",
campaign: "june-launch",
content: "cta-button"
});
// https://myapp.com/pricing?utm_source=email&utm_medium=newsletter&...Why you still need a URL shortener
UTM URLs are long. Very long. Pasting them in Slack, emails, or printed materials looks unprofessional and some platforms truncate them. A URL shortener creates a clean link that redirects through your long UTM URL:
// Long UTM URL โ clean short link "https://myapp.com/pricing?utm_source=email&utm_medium=newsletter&utm_campaign=june-launch" โ "https://myapp.com/go/launch" // custom short URL
Tracking in your own backend
If you build your own redirect endpoint, you can log every click with server-side context that client-side analytics can't capture:
// Express redirect handler
app.get("/go/:code", async (req, res) => {
const link = await db.links.findByCode(req.params.code);
if (!link) return res.status(404).send("Not found");
await db.clicks.create({
linkId: link.id,
ip: req.ip,
userAgent: req.headers["user-agent"],
referer: req.headers.referer,
timestamp: new Date(),
});
res.redirect(301, link.destination);
});