Campaign Links & QR Codes
Part of the campaign operations system at /docs
What this system does
Every QR code and tracked link in the campaign passes through ryangrissinger.com/q/{slug}. When someone scans or clicks, the server records a scan count and redirects them to the real destination with UTM parameters appended. This gives the campaign:
- A registry of every tracked link ever created
- The ability to change a destination URL without reprinting materials
- Native scan counts independent of JavaScript
- Full Google Analytics 4 attribution via standard UTM parameters
URL structure
All redirect URLs follow this pattern:
https://ryangrissinger.com/q/{slug}
The slug is short, lowercase, hyphenated — e.g. bc-2026, palm-spring, fb-primary. Once a QR code is printed, the slug is permanent. Destinations and UTM parameters can be updated without regenerating the QR code.
How to create a new campaign link
- Go to Campaign Links in the admin navigation.
- Click New Link.
- Fill in Name, Slug (auto-suggested from name — you can edit it), and Destination URL.
- Fill in the UTM parameters (see conventions below).
- If this is a print material, select the Material Type and add vendor notes.
- Click Create Link.
- On the edit page, click Generate QR Code to produce the 400×400 PNG for your designer.
Scan counts vs. Google Analytics
| Metric | Where to look | What it measures |
|---|---|---|
| Raw scans | Admin → Campaign Links → Scans column | Every redirect hit, including users who don't load the page (no JS required) |
| Sessions, conversions | Google Analytics → Acquisition → Campaigns | Visitors who fully loaded the page; includes bounce rate, conversions, device type |
Use raw scans to compare which print materials drive the most initial engagement. Use GA4 for everything downstream: conversion rates, signup completions, device breakdown.
UTM conventions for this campaign
Always use these agreed values so reports are consistent across all channels.
utm_medium
| Value | Use for |
|---|---|
print | Any physical printed material |
social | Organic social media posts |
email | Email campaigns and newsletters |
paid | Paid advertising (Google, Meta, etc.) |
organic | Non-paid digital (QR on website, etc.) |
utm_source (print materials)
| Value | Material |
|---|---|
business_card | Business cards |
palm_card | Palm cards / literature drops |
door_hanger | Door hangers |
flyer | Flyers and posters |
yard_sign | Yard sign inserts |
utm_source (digital channels)
| Value | Channel |
|---|---|
facebook | Facebook posts and bio |
instagram | Instagram posts and bio |
twitter | Twitter / X posts |
nextdoor | Nextdoor posts |
linkedin | LinkedIn posts |
mailchimp | Third-party email tools |
utm_campaign naming
Format: {descriptor}_{year} — all lowercase, underscores, no spaces.
spring_2026— spring canvassing and literature drop seasonprimary_2026— primary election periodfiling_2026— around filing deadlinegeneral_2026— general election period
utm_content
Use to differentiate versions of the same material: front, back, v2, header, footer.
QR code specs
- Size: 400×400px PNG (scale down in design software as needed)
- Error correction: M level (15%) — good balance for print
- Margin: Minimal (add quiet zone in your layout)
- Always test: Scan with at least two different phones before sending to print
Legacy QR codes
Five QR codes from before this system was built are registered as legacy entries. Their original static images remain in public/images/ and continue to work. When these materials are reprinted, generate new redirect-based QR codes using the next version slug (e.g. palm-v2) and track them through this system going forward.