Skip to content
UseQR
ESC

Jump to

MOVEOPEN50 places

How-to guides

How to make one QR code do different things by device

Encode a single URL on a domain you control and branch there: the server or a small script inspects the user agent and redirects iPhones to the App Store, Android to Play, and everyone else to a landing page. It works, but the redirect must stay alive as long as the print does.

View as MarkdownPaste this page into any AI assistant. It is plain, portable Markdown.

The architecture: one code, one URL, one branch point

A QR code cannot detect devices. It is inert data. The branching happens at the URL it opens. So the pattern is always:

One printed code → https://example.com/get → inspect User-Agent → redirect

The classic use is app distribution: one code on the poster, iPhones land on the App Store, Android lands on Google Play, laptops land on a page with both badges. The same mechanism serves platform-specific deep links, OS-specific help pages, or mobile-vs-desktop experiences.

Client-side version (simplest to deploy)

A static HTML page at the encoded URL, a few lines of script:

<script>
  var ua = navigator.userAgent;
  if (/iPhone|iPad|iPod/.test(ua)) {
    location.replace("https://apps.apple.com/app/id0000000000");
  } else if (/Android/.test(ua)) {
    location.replace("https://play.google.com/store/apps/details?id=com.example.app");
  }
  // no match: stay on this page, which shows both store badges
</script>

Falling through to a visible page with both buttons is the load-bearing detail. It is your safety net for everything the sniffing gets wrong.

Server-side version (cleaner)

A 302 issued by the server: a redirect rule, an edge middleware, or a tiny serverless function, avoids the blank flash of the client-side page, works with JavaScript disabled, and gives you a log line per scan, which is free analytics into the bargain. Same logic, same fallback: anything unmatched gets the landing page, not a guess.

The honest caveats

  • User-agent sniffing is approximate. The canonical trap: iPadOS Safari requests desktop sites by default and identifies itself like a Mac, so naive rules send iPads to your desktop page instead of the App Store. Treat misclassification as normal and let the fallback page absorb it.
  • You are now running a redirect service. The printed code is only as alive as example.com/get. That endpoint must survive redesigns, replatformings and staff changes for the life of the print, the same permanence contract discussed in changing what a code points to.
  • Hosted "smart link" products carry platform risk. Third-party device-routing services exist, but you inherit their lifespan: Google's Firebase Dynamic Links (once the standard answer here) was shut down in 2025. Ten lines on your own domain have no such expiry; the general argument is in static vs dynamic.

For the common app-install case, start from the app download QR generator; for anything custom, encode with the URL generator and confirm the final payload in the validator. Then test the full matrix before printing: an iPhone, an Android phone, an iPad (it will surprise you), and a laptop.

FAQ

Can a QR code detect what phone scanned it?

No: the code is static data. The detection happens at the URL it opens, where a server or script inspects the browser's user agent and redirects accordingly.

How do I make one QR code open the right app store?

Encode a URL you control; at that URL, redirect Apple devices to the App Store, Android to Google Play, and show everyone else a page with both badges. The fallback page catches every device the rules misread.

Why does my iPad get the wrong destination?

iPadOS Safari requests desktop websites by default and presents a Mac-like user agent, so simple rules classify iPads as desktops. Design the fallback page to serve them well rather than fighting the user agent.

Is there a service that does device routing for me?

Several exist, including dynamic QR platforms, but the printed code then depends on their continued operation, and such services do shut down. A short redirect on your own domain does the same job without an expiry date you don't control.

Try it: free, no signup

  • How to change what a QR code points to, The modules are the data: a printed static code can't be re-encoded. Your real options: change a redirect you control, reprint, or plan dynamic next time.
  • How to track QR code scans without a paid tool, Point the code at a URL on your own domain carrying UTM parameters, and read the results in your own analytics. That gives you scan counts, timing and…
  • Static vs dynamic QR codes, A static QR code contains its destination directly, so it never expires and cannot be tracked or edited. A dynamic code contains a short link that…
  • QR codes in serverless functions, Generating QR codes in Lambda, Cloudflare Workers and Vercel functions: bundle size, native dependency pitfalls, streaming, and when to skip the function entirely.