# Mobile App Landing Page Template: QR Code and Store Links

> Build a mobile app landing page template in React: store buttons on the first screen, a QR code for desktop visitors and one link that opens the right store.

- Author: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Published: Nov 6, 2026
- Category: [Build it: screens and apps](https://wingo-ui.com/blog/category/build)
- Reading time: 9 min
- Canonical: https://wingo-ui.com/blog/mobile-app-landing-page-template

## TL;DR

A mobile app landing page has one job: get the visitor to the right store in as few taps as possible. That means store buttons in the first screen on a phone, a QR code for desktop visitors (who cannot install from a laptop), and one short link that sends iPhones to the App Store and Android phones to Google Play. In Next.js, the Wingo UI App Download Section and Download Page template build that page from props, with a phone drawn in code that follows light and dark mode.

You built the app, the store listings are approved, and now you need a page that sells it. Search for a mobile app landing page template and you get HTML themes, Figma kits and a few React options. As of November 6, 2026, the [Magic UI Pro Mobile template](https://pro.magicui.design/docs/templates/mobile) runs on Next.js 14, React 18.3 and Tailwind 3.4 with store badges built in, [TailGrids AppSpace](https://tailgrids.com/templates/app-space) is a paid React and Tailwind template with download buttons in the hero, and a free [Astro theme](https://astro.build/themes/details/mobile-app-landing-page/) fetches the rating, version and description from the App Store. None of their feature pages mentions two things an app page needs: a QR code for the desktop visitor and one link that opens the right store on each phone.

This guide covers what an app download page has to do, how two pieces of Wingo UI (the library we build) handle it, and what to check at 390px. The pieces are the [App Download Section](https://wingo-ui.com/components/app-download-section) and the [Download Page template](https://wingo-ui.com/templates/download-page), and the code targets the Next.js 16 App Router, React 19 and Tailwind v4.

## What does a mobile app landing page need to do?

Get the visitor to the store. Everything else supports that one tap. Good app download page design comes down to four jobs, and each one changes with the device the visitor holds:

| Job | On a phone | On a desktop |
|---|---|---|
| Show the app | A drawn phone or one screenshot, under the copy | The phone beside the copy, with a notification floating next to it |
| Get the install | Store buttons in the first screen, at least 44px tall | Store buttons plus a QR code to scan with the phone |
| Prove it is good | Store rating and review count under the buttons | The same, plus features beside the phone |
| Answer doubts | FAQ: price, devices, offline, privacy | The same |

The desktop row is the one most templates miss. Someone who found your app on a laptop cannot install it there. Without a QR code they have to search the store on their phone and hope they pick your app and not a clone with a similar icon.

## How do you build the app download section in React?

Install the block. The CLI adds its dependencies too, including the [QR Code](https://wingo-ui.com/components/qr-code) component and the read-only rating:

```bash
npx wingo-ui@latest add app-download-section
```

The block ships with `"use client"`. Keep your instance in its own client file, as below, so the page that renders it stays a server component and can export `metadata`. Pass your real store links, the URL the QR code opens and your features:

```tsx
// app/(marketing)/app-landing.tsx
"use client";

import Link from "next/link";
import { Bell, Play, Smartphone, WifiOff } from "lucide-react";
import { AppDownloadSection } from "@/components/blocks/app-download-section";

export function AppLanding() {
  return (
    <AppDownloadSection
      headingAs="h1"
      linkComponent={Link}
      eyebrow="iOS and Android"
      title="Your grocery list, shared with everyone at home"
      description="Add an item on the bus, and it shows up on your partner's phone before they reach the store."
      qrValue="https://acme.com/get"
      rating={4.7}
      reviewCount={3200}
      radius="full"
      stores={[
        { caption: "Download on the", label: "App Store", href: "https://apps.apple.com/app/id000000000", icon: <Smartphone /> },
        { caption: "Get it on", label: "Google Play", href: "https://play.google.com/store/apps/details?id=com.acme.list", icon: <Play /> },
      ]}
      features={[
        { icon: <WifiOff />, title: "Works offline", description: "Edits sync when you are back online." },
        { icon: <Bell />, title: "Quiet notifications", description: "Only when someone adds to a list you follow." },
      ]}
    />
  );
}
```

`headingAs="h1"` makes it the page's first heading, so the section can be the whole first screen. In `split` the features list sits between the description and the store buttons, so keep it to two short items (or pass `features={[]}`) if the buttons must be visible on a phone without scrolling. Use your real rating and review count from the store console, or set `showRating={false}` until you have them. A made-up 4.9 is the kind of claim a visitor checks in one tap.

> Live demo (App Download Section): Switch the layout between split, centered and card, then narrow the window below 1024px: the QR code disappears and the store buttons stay, sized for a thumb. Try it at [App Download Section](https://wingo-ui.com/components/app-download-section) and install it with `npx wingo-ui@latest add app-download-section`.

### Which layout fits your app?

`layout` takes three values. `split` puts copy, features and downloads beside the phone and works as a hero. `centered` puts the heading and buttons on top with the phone between two feature columns, which suits a section lower on a longer page. `card` puts everything on a tone panel with the phone rising from its bottom edge, a good closing band. `reverse` moves the phone to the left in `split` from 1024px.

## How do you draw device shots in code instead of screenshots?

The section draws the phone with CSS and design tokens: a frame, a camera pill, a status bar and a mini app with a progress card and a task list. Because it is drawn, it follows light and dark mode, stays sharp on every screen and never shows last quarter's UI. You change its copy through the `phone` prop (time, heading, user, tasks, the notification) and its frame color through `phoneColor`.

When your real app looks different, and it will, pass a screenshot through `screen`. It replaces only the inside of the phone, so the frame and the floating notification stay:

```tsx
import Image from "next/image";
import { AppDownloadSection } from "@/components/blocks/app-download-section";

<AppDownloadSection
  screen={<Image src="/shots/list-home.png" alt="" width={390} height={844} className="size-full object-cover" />}
  phoneColor="#1F2937"
/>
```

The `alt` is empty because screen readers hear the phone as one image and skip its screen. The default description talks about the drawn task list, so describe your screenshot instead with `labels={{ phone: "..." }}`. Export the screenshot at the phone's aspect ratio so `object-cover` crops nothing important.

## How do you make one link that opens the right store?

The QR code, your ads and your emails should all point to one URL. Add a route handler that reads the user agent and redirects:

```ts
// app/get/route.ts
const APP_STORE = "https://apps.apple.com/app/id000000000";
const GOOGLE_PLAY = "https://play.google.com/store/apps/details?id=com.acme.list";

export function GET(request: Request) {
  const ua = request.headers.get("user-agent") ?? "";
  if (/iphone|ipod/i.test(ua)) return Response.redirect(APP_STORE, 302);
  if (/android/i.test(ua)) return Response.redirect(GOOGLE_PLAY, 302);
  // ipads report a mac user agent by default, so they land on the download page
  return Response.redirect(new URL("/download", request.url), 302);
}
```

A 302 keeps the target easy to change later. Scanning the QR code on the landing page now opens the store listing directly on the visitor's phone, with no second search. For QR styling, such as a logo in the center that still scans, see our [React QR code with logo guide](https://wingo-ui.com/blog/react-qr-code-with-logo).

On iPhone you can also add Safari's Smart App Banner. In Next.js it is one metadata field, which renders the `apple-itunes-app` meta tag:

```tsx
// app/(marketing)/page.tsx
import type { Metadata } from "next";
import { AppLanding } from "./app-landing";

export const metadata: Metadata = {
  title: "Acme List for iPhone and Android",
  itunes: { appId: "000000000" },
};

export default function Page() {
  return <AppLanding />;
}
```

## Can you use the official App Store and Google Play badges?

Yes, if you follow each store's rules. As of November 6, 2026, the App Store badge guidelines in [Apple's marketing guidelines](https://developer.apple.com/app-store/marketing/guidelines/) say to use only the badge artwork Apple provides, not to modify, angle or animate it, to keep clear space of a quarter of the badge height around it, to show it at least 40px tall on screen and to place it first when other store badges appear. Google's [Google Play badge guidelines](https://partnermarketinghub.withgoogle.com/brands/google-play/google-play/lockups-icons-badges/) ask for the same quarter-height clear space, a minimum height of 28px, and a Google Play badge the same size or larger than the other badges next to it.

The App Download Section does not ship those logos. Its store buttons are generic links with a lucide glyph and the store name, 56px tall on phones and 52px from 640px. To use the official artwork, hide the built-in buttons and pass your badges as `actions`:

```tsx
<AppDownloadSection
  stores={[]}
  actions={
    <div className="flex flex-wrap items-center gap-3">
      <a href="https://apps.apple.com/app/id000000000">
        <img src="/badges/app-store.svg" alt="Download on the App Store" className="h-12 w-auto" />
      </a>
      <a href="https://play.google.com/store/apps/details?id=com.acme.list">
        <img src="/badges/google-play.svg" alt="Get it on Google Play" className="h-12 w-auto" />
      </a>
    </div>
  }
/>
```

Both images get the same height, with the App Store badge first and `gap-3` (12px) of space, which covers a quarter of a 48px badge. If your Google Play file carries transparent padding, crop it or raise its height so the badge does not render smaller than Apple's.

## When do you need the full Download Page template?

Use it when the app also ships for Mac, Windows, Linux, a browser or the command line. The [Download Page](https://wingo-ui.com/templates/download-page) template composes the App Download Section with an OS-aware hero, a platform picker, install commands, checksums, release notes and system requirements. After hydration its main button follows the visitor's device, so an iPhone sees "Download on the App Store" and an Android phone "Get it on Google Play" instead of a Mac download. The server always renders macOS, so the markup never mismatches, and the client catches iPads (which report a Mac user agent) with a touch check the server cannot do.

> Live demo (Download Page): This version is pinned to iPhone: the hero button offers the App Store, and the iPhone tab in the picker shows a QR code and three install steps. Press the download button to see the thanks state. Try it at [Download Page](https://wingo-ui.com/templates/download-page) and install it with `npx wingo-ui@latest add download-page`.

The template does not navigate on its own. It calls `onDownload(platform, variant, channel)` and you decide where to go:

```tsx
// app/(marketing)/download/download-route.tsx
"use client";

import Link from "next/link";
import { DownloadPage } from "@/components/templates/download-page";

const STORES: Record<string, string> = {
  "ios:app-store": "https://apps.apple.com/app/id000000000",
  "android:play": "https://play.google.com/store/apps/details?id=com.acme.list",
};

export function DownloadRoute() {
  return (
    <DownloadPage
      header={false}
      footer={false}
      linkComponent={Link}
      ctaTone="brand"
      mobileProps={{ qrValue: "https://acme.com/get" }}
      onDownload={(platform, variant) => {
        const url = STORES[`${platform}:${variant}`];
        if (url) window.open(url, "_blank", "noopener");
      }}
    />
  );
}
```

Pass your own `platforms` array to list only what you ship, and turn off the sections you have no content for: `showRequirements`, `showEnterprise` and `showFeatures` (the desktop features) all take `false`.

## Where does the Hero Section fit?

Use the [Hero Section](https://wingo-ui.com/components/hero-section) instead of the App Download Section at the top when the app is one part of a product that also runs on the web, so the first screen sells the product and the app comes lower. Point its primary action at the store link and put a phone screenshot in `media`:

```tsx
import Image from "next/image";
import Link from "next/link";
import { HeroSection } from "@/components/blocks/hero-section";

<HeroSection
  layout="split"
  linkComponent={Link}
  title="Plan the week together, on any device"
  labels={{ primary: "Get the app", secondary: "Open in the browser" }}
  hrefs={{ primary: "/get", secondary: "/sign-in" }}
  media={<Image src="/shots/list-home.png" alt="The Acme List app on a phone" width={780} height={1688} className="mx-auto h-auto w-64" />}
/>
```

Then an App Download Section with `layout="centered"` further down repeats the stores and adds the QR code. Our [shadcn hero section guide](https://wingo-ui.com/blog/shadcn-hero-section) covers the other hero layouts.

## What breaks on a 390px phone?

Usually the first screen: too much copy above the store buttons pushes them below the fold. Check these on a real phone before you launch:

- **The first screen.** Title, one line of description and both store buttons visible without scrolling. If not, cut the description.
- **The buttons.** At least 44px tall and far enough apart that a thumb does not hit both. The section's buttons are 56px tall on phones, share the row and wrap onto two lines when it gets too narrow.
- **The QR code.** Hidden. The section shows it from 1024px only, which is right: a phone cannot scan itself.
- **The picture.** The drawn phone goes under the copy and the floating notification hides at narrow widths, so nothing forces a sideways scroll.
- **Web app visitors.** If your product is also a PWA, do not stack an install prompt on top of the store buttons. Our [React PWA install prompt guide](https://wingo-ui.com/blog/react-pwa-install-prompt) covers when each one makes sense.

## How should the page end?

With the questions people ask before they install, then one last download button. Cover the doubts first: is it free, which devices, does it work offline, what happens to my data. The free [FAQ Section](https://wingo-ui.com/components/faq-section) takes them as `items` and can emit FAQ JSON-LD with `jsonLd`. The free [CTA Section](https://wingo-ui.com/components/cta-section) closes the page with a solid band (`variant="inverted"`, the default); point its `hrefs.primary` at `/get`.

For a whole marketing site around the app, the [Landing Page template](https://wingo-ui.com/templates/landing-page) composes the same marketing sections. More full pages are in the [Build it category](https://wingo-ui.com/blog/category/build), starting from its pillar, the [Next.js admin dashboard tutorial](https://wingo-ui.com/blog/nextjs-admin-dashboard-tutorial).

## Next step

The App Download Section, Download Page template and Hero Section come with [Pro](https://wingo-ui.com/pricing) ($8 a month, $80 a year or $150 once); the FAQ and CTA sections are free with a free account. Start with `npx wingo-ui@latest add app-download-section`, pass your store links and the `/get` URL, and scan the QR code with your own phone before anyone else does.

## Components in this post

- [App Download Section](https://wingo-ui.com/components/app-download-section) (Pro): A mobile app promo: a drawn phone with a mini app, store buttons, a QR code to the download page, the rating and feature bullets. Install: `npx wingo-ui@latest add app-download-section`
- [Download Page](https://wingo-ui.com/templates/download-page) (Pro): A React app download page template: an OS-aware download hero, drawn desktop and phone apps, a platform picker with checksums, and FAQ. Install: `npx wingo-ui@latest add download-page`
- [Hero Section](https://wingo-ui.com/components/hero-section) (Pro): A React hero section for a landing or product page: an announcement pill, a big title, two actions, social proof and a product shot drawn in code. Install: `npx wingo-ui@latest add hero-section`
- [QR Code](https://wingo-ui.com/components/qr-code) (Pro): A React QR code generator with rounded or dotted modules, soft eyes, a center logo, any colors, a caption and one-tap PNG or SVG export. Install: `npx wingo-ui@latest add qr-code`
- [FAQ Section](https://wingo-ui.com/components/faq-section) (Free): A React FAQ section for marketing pages: an accordion, a split layout, an open grid or expandable cards, with topics and live search. Install: `npx wingo-ui@latest add faq-section`

## FAQ

### What should a mobile app landing page include?

A headline with store buttons in the first screen, a picture of the app, three or four features, proof such as the store rating, an FAQ about price, devices and privacy, and a closing call to action. Desktop visitors also need a QR code, because they cannot install a phone app from a laptop.

### How do I send iPhone users to the App Store and Android users to Google Play from one link?

Add a route handler such as /get that reads the user agent and redirects with a 302: iPhone and iPod to the App Store, Android to Google Play, everything else to your download page. Use that one URL in the QR code, ads and emails.

### Can I use my own button instead of the official App Store badge?

Not for the App Store: Apple's marketing guidelines say to use only the badge artwork Apple provides and not to modify it. The App Download Section draws generic store buttons with a glyph and the store name, so for the official badges pass an empty stores array and put the badge images in the actions prop.

### Is there a free mobile app landing page template for Next.js?

In Wingo UI the App Download Section, Download Page template and Hero Section are Pro, while the FAQ Section, CTA Section and Marketing Header are free with a free account. Outside Next.js, astro.build lists a free Mobile App Landing Page theme built with Astro and React (checked November 6, 2026).

### Should the QR code show on phones?

No. A visitor on a phone cannot scan their own screen, so the code only wastes space. The App Download Section shows it from 1024px and gives phones the store buttons only.

---

Source: https://wingo-ui.com/blog/mobile-app-landing-page-template
