Skip to main content
QR & printBy SendURL team16 min read

Custom Short Link Slugs: Naming Rules That Work in Print

Part of the QR & print handbook

What makes a good custom short link: the seven rules, SendURL's exact slug rules, why case matters, which characters to avoid, and naming patterns with examples for launches, sales, podcasts, events and print.

A good custom short link slug is lowercase, made of one to three real words joined by hyphens, free of characters that look alike, and used for exactly one placement. On SendURL a slug is 1 to 32 letters, digits, hyphens or underscores, it is case-sensitive, and it can never be changed after the link is created, so the choice matters most for links that get printed, typed or read aloud.

The slug is the part after the domain: in snu.to/autumn-sale-ig-bio it's autumn-sale-ig-bio. The domain is always snu.to; SendURL has no custom domains. This guide is part of the QR and print handbook, next to how to track QR code scans, and it's linked from the social media link tracking handbook, because slugs matter most wherever people have to type a link.

Random or custom slug?

Every SendURL link gets a random slug unless you type one. Random slugs are letters (both cases) and digits: five characters from the API and the home page (snu.to/x7Kp2), six from the console form (snu.to/aZ3k9Q).

Use a random slug whenUse a custom slug when
People will only tap it: emails, chat messages, postsPeople will type it: posters, slides, business cards, packaging
You create links in bulk from codeSomeone will read it out: podcasts, talks, radio, phone calls
It's only ever a QR code, never shown as textYou'll read the report later and want to know which link is which
The link is a one-off you'll never look at againSeveral placements share one destination and need separate counts

A random slug is also the shortest option, which keeps a QR code small. It isn't secret, though: anyone who sees the link can open it. If a link must stay private, protect it with a password rather than counting on a slug nobody will guess.

7 rules for a good slug

  1. Lowercase only. Paths are case-sensitive; snu.to/Menu is not snu.to/menu.
  2. Hyphens between words. spring-menu, not springmenu or spring_menu.
  3. One to three real words, under about 15 characters. Every character is one more someone can mistype.
  4. No look-alike characters. Avoid mixing 0 and o, 1 and l, or rn where m would also read.
  5. One slug per placement. The poster and the Instagram bio each get their own link, so each gets its own count.
  6. Nothing private in it. Slugs are public: no customer names, email addresses or order numbers.
  7. Final before it's printed. A slug can't be changed, so check it, test it, then print.

The rest of this guide explains each rule and gives patterns to copy.

SendURL's slug rules

RuleDetail
Length1 to 32 characters
Charactersa–z, A–Z, 0–9, hyphen -, underscore _. No spaces, dots, slashes, accents or emoji
CaseCase-sensitive: Launch and launch are different slugs, and can belong to different people
Reservedhealth, api, docs, robots.txt, favicon.ico, sitemap.xml, _next, in any letter case
UniquenessAcross all of SendURL, not per account, because every link shares the snu.to domain
Changing itNot possible after the link is created. The destination can change through the API
Deleting the linkFrees the slug for anyone. Disable a link instead if it was ever printed or shared

When a slug breaks a rule, the API answers 400 validation_error with the reason in issues ("Slug must be 1-32 characters: letters, digits, '-' or '_'", or "That slug is reserved"). A slug someone already has is 409 slug_taken: "That slug is already taken — try another." The Create a link reference lists every field, and custom and random slugs covers the same rules in the console.

Case sensitivity, explained

The standard for URLs (RFC 3986) says the scheme and host "are case-insensitive", while "the other generic syntax components are assumed to be case-sensitive" (section 6.2.2.1). So SNU.TO/menu and snu.to/menu are the same address, but snu.to/Menu is a different one. Google treats paths the same way: it "treats both /APPLE and /apple as distinct URLs" (URL structure, updated 10 December 2025).

On SendURL that has two practical effects:

  • A reader who types snu.to/Autumn-Sale from a poster when the link is autumn-sale gets the "Link not found" page, and you never see the attempt.
  • Someone else can create snu.to/Autumn-Sale as their own link. Your visitor who types the capitals lands on their page.

Lowercase removes both problems: there is only one way to type it. Mixed-case random slugs are fine for links people tap, because nobody types them.

Avoid look-alike characters

Some characters are hard to tell apart in print, in small type, or in a font you didn't pick. Crockford's Base32, a scheme designed for codes people copy by hand, leaves out I and L because they "can be confused with 1" and O because it "can be confused with 0" (Crockford Base32).

Looks likeExample to avoidBetter
0 and o, Osnu.to/2o20-promosnu.to/promo-2020
1, l and Isnu.to/l1nkssnu.to/links
rn and msnu.to/modern-barn in a narrow fonttest it in the print font
5 and S, 2 and Z, 8 and Bsnu.to/S5-offersnu.to/summer-offer
vv and wsnu.to/vvinesnu.to/wine
- and _snu.to/spring_menu (the underscore vanishes when the link is underlined)snu.to/spring-menu

Lowercase-only removes the capitals (I, O, S, Z, B) from the problem. The rest you catch by reading the slug in the font it will be printed in.

Slugs people will type or hear

A link on a poster, a slide or in a podcast has to survive being read, remembered for a few seconds and typed on a phone. Some habits that help:

  • Say it out loud before you pick it. "snu dot to slash e-p forty-two" works. "snu dot to slash e-p underscore four two dash notes" doesn't.
  • Digits or words, not both for the same number. ep42 is fine; avoid four-ep next to ep4 in the same show.
  • Avoid homophones. 2, to and too, or 4 and for, invite the wrong one. deal-for-you heard on a podcast could be typed several ways.
  • Hyphens are "dash" to most listeners. If a slug needs more than two dashes, it's probably too long to say.
  • Show it as text. Under every QR code, print the link itself (snu.to/menu-window) for people who'd rather type it, and so the code clearly says where it goes.

For QR codes there's a size bonus too: slugs of 1 to 9 characters keep a SendURL code at 25×25 modules, and 10 to 25 characters at 29×29 (QR code size for print has the numbers).

Readable slugs and trust

People hesitate over short links because the link hides where it goes, and phishers use exactly that. The US Federal Trade Commission's advice is to "inspect the URL before you open it" when a QR code turns up somewhere unexpected (FTC, 6 December 2023).

A slug can't prove anything, but it can avoid looking wrong:

  • Match the context. snu.to/menu-table on a table card reads as part of the card. snu.to/x7Kp2 on the same card reads as nothing.
  • Avoid phishing words. login, verify, account, secure, password and update in a slug are the vocabulary of scam messages. Your link may be honest; it will still look like the other kind.
  • Never name another company. A slug like paypal-refund or bank-alert is how abuse looks, and links reported through the abuse form can be taken down.

What a slug can't change: the domain is snu.to, not yours. SendURL has no custom domains and no link preview page, so the slug and the text around the link are what tell people it's yours. Short link safety covers the other side, checking a link before you open it.

You'll see figures such as "39% more clicks" quoted for branded links. They come from vendors' marketing pages with no published method, so we don't use them. The research that exists is about search results: a 2007 Microsoft Research study found that features of a result's caption, including the length of the URL shown, "can significantly influence users' Web search behavior" (Clarke et al., SIGIR 2007). That's search results, not short links, and it gives no percentage for them. Pick readable slugs because people have to read, type and trust them, not because of a number.

A naming pattern that scales

For campaigns, one pattern covers almost everything:

Text
<campaign>-<channel>[-<placement or variant>]

Campaign first, so the links of one campaign sit together when you sort or search your links. Channel second, placement or variant last. Keep each part to one or two words.

Campaign typeExample slugs
Product launchaurora-launch-ig-bio, aurora-launch-email, aurora-launch-li, aurora-launch-poster
Seasonal saleautumn-sale-ig-bio, autumn-sale-story-oct14, autumn-sale-sms, autumn-sale-window
Newsletternews-2026-10, news-2026-10-cta, news-2026-10-footer
Podcasttsp-ep42, tsp-ep42-notes, tsp-ep42-sponsor (a show prefix, because ep42 alone is likely taken)
Conference or eventdevcon-booth, devcon-slides, devcon-badge, devcon-raffle
Restaurant or shopmenu-window, menu-table, menu-bag, menu-receipt
Print runsflyer-oct-a5, flyer-nov-a5, box-insert-2026
Creators and affiliatesautumn-sale-priya, autumn-sale-tom, one per creator
Message testsautumn-a, autumn-b (see A/B testing with short links)
Job applicationscv-acme, cv-globex, one per application
Support and docssetup-guide, returns, warranty-form
Webinarswebinar-nov-signup, webinar-nov-replay

Some notes on the details:

  • Length. Campaign slugs run past 15 characters, and that's fine for links people only tap. Keep the ones people type (posters, slides, podcasts) short.
  • Dates. 1014 reads as 14 October in some countries and nonsense in others. Use oct14, or 2026-10 for months.
  • Channels. Pick one short code per channel and keep it: ig, tt, li, yt, x, email, sms, qr, poster. Write the list down.
  • Placements beat channels. "Instagram" is too coarse when you have five bio links and daily Stories: ig-bio, ig-story-oct14, ig-dm.
  • People. A link per person (cv-acme) tells you a click happened, not who clicked, and in the EU tracking an individual is processing personal data. If you track per person, say so. Can you see who clicked your link? covers what a click does and doesn't show.

The slug is for humans and for reading your link report. If you also use Google Analytics, the UTM parameters on the destination carry the same information in GA4's format; a UTM naming convention explains how the two fit together. Don't put UTMs in the slug.

Taken, reserved and rejected slugs

Slugs are global on snu.to. Short, common words (sale, menu, promo, ep1) are the first to go, so expect a 409 slug_taken and plan for it:

  • Add your name or brand. acme-sale, marios-menu.
  • Add the year or season. sale-2026, autumn-sale.
  • Add the placement. menu-window is far more likely to be free than menu, and more useful.

Reserved words are refused in any case (API, Docs, HEALTH), and anything outside A–Z a–z 0–9 - _ or longer than 32 characters is a 400. A random slug can, very rarely, collide with an existing one; sending the same request again gets a new one.

Never reuse a printed slug

A slug means one thing for as long as copies of it exist. Flyers stay on noticeboards for months, packaging for years, and screenshots forever.

  • New campaign, new slug. Don't repoint autumn-sale-2026 at next spring's sale; old flyers would send people to an offer that never appeared on them. Create spring-sale-2027.
  • Same thing, new address: change the destination. If the menu page moves, change where the link points and every printed code follows.
  • Over: expire or disable it. An expiry date shows "Link expired" from the moment the offer ends; disabling shows "Link not found" and keeps the slug yours.
  • Never delete it. Deleting frees the slug, and anyone can register snu.to/autumn-sale-2026 and receive the scans from your flyers.

The REST API is on every plan. Send slug in the body:

Create a link with a custom slugShell
curl -X POST https://api.sendurl.to/api/v1/links \
  -H "Authorization: Bearer $SENDURL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"destinationUrl": "https://example.com/autumn-sale", "slug": "acme-autumn-sale-2026"}'
409 when someone already has itJSON
{ "error": "slug_taken", "message": "That slug is already taken — try another." }

In code, try a short list of candidates in order and stop at the first free one. Node 18 or later, no packages:

first-free-slug.mjsJavaScript
const API = "https://api.sendurl.to/api/v1";

async function createWithFirstFreeSlug(destinationUrl, slugs) {
  for (const slug of slugs) {
    const res = await fetch(`${API}/links`, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.SENDURL_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ destinationUrl, slug }),
    });
    if (res.status === 409) {
      console.log(`${slug} is taken`);
      continue;
    }
    // Read the status before parsing: a 429 from Cloudflare is HTML, not JSON.
    if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
    return res.json();
  }
  throw new Error("every candidate slug is taken");
}

const link = await createWithFirstFreeSlug("https://example.com/autumn-sale", [
  "autumn-sale",
  "acme-autumn-sale",
  "acme-autumn-sale-2026",
]);
console.log(link.shortUrl);

Check slugs before you create them

When a sheet of placements becomes a batch of links, a lint step catches the mistakes the API allows: capitals, underscores and look-alikes are all valid slugs. This Python check flags them:

lint_slugs.pyPython
import re
import sys

RESERVED = {"health", "api", "docs", "robots.txt", "favicon.ico", "sitemap.xml", "_next"}
WORDS_WITH_HYPHENS = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")


def problems(slug):
    found = []
    if not re.fullmatch(r"[A-Za-z0-9_-]{1,32}", slug) or slug.lower() in RESERVED:
        found.append("SendURL will reject it")
    if slug != slug.lower():
        found.append("has capitals")
    if not WORDS_WITH_HYPHENS.match(slug.lower()):
        found.append("use single hyphens between words, no underscores")
    for word in re.split(r"[-_]", slug.lower()):  # look-alikes side by side in one word
        if "0" in word and "o" in word:
            found.append(f"'{word}' mixes 0 and o")
        if "1" in word and re.search(r"[li]", word):
            found.append(f"'{word}' mixes 1 with l or i")
    if len(slug) > 15:
        found.append(f"{len(slug)} characters; can it be shorter?")
    return found


for slug in sys.argv[1:]:
    print(f"{slug:24} {'; '.join(problems(slug)) or 'ok'}")
python3 lint_slugs.py menu-window Spring_Menu l1nks-2o20 autumn-sale-ig-bio-oct14Text
menu-window              ok
Spring_Menu              has capitals; use single hyphens between words, no underscores
l1nks-2o20               'l1nks' mixes 1 with l or i; '2o20' mixes 0 and o
autumn-sale-ig-bio-oct14 24 characters; can it be shorter?

Checklist

  • Custom slug only where people type, hear or read it; random everywhere else
  • Lowercase, hyphens, one to three words, under about 15 characters
  • No 0/o, 1/l/i mixes; read in the print font
  • Said out loud once, if it'll be spoken
  • Follows the pattern <campaign>-<channel>[-<placement>], with your written list of channel codes
  • One slug per placement, creator or variant
  • Nothing private: no names, emails or order numbers
  • No phishing words, no other company's name
  • Short link printed as text next to every QR code
  • Created and tested before the print file is sent; it can't change afterwards
  • Old campaigns expired or disabled, never deleted

Shorten a link on the home page to see a random slug without an account; custom slugs come with a free account.

Frequently asked questions

How long should a custom short link be?

As short as it can be while still saying what it is: one to three words, ideally under 15 characters. SendURL allows 1 to 32 characters. Slugs of 9 characters or fewer also keep the QR code at its smallest size.

Should I use hyphens or underscores in a slug?

Hyphens. They are easier to say, easier to see, and Google recommends them over underscores for separating words in URLs. An underscore also disappears when a link is shown underlined.

Can I change a short link's slug later?

Not on SendURL. The slug is fixed once the link exists, because printed QR codes and copies of the link depend on it. You can change where it points through the API, or create a new link and disable the old one.

Is a custom short link the same as a branded short link?

No. A branded short link usually means a short link on your own domain. SendURL doesn't offer custom domains: every link is on snu.to, and the custom part is the slug after the slash.

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