DocsExample: PWA Store

Example: PWA Store

PWARegistry provides:

  • app identity (name, description)
  • categories
  • icons
  • mobile screenshots
  • desktop screenshots
  • PWA status
  • normalized technical data

Your store provides:

  • branding
  • design
  • navigation
  • search UI
  • featured sections
  • rankings
  • reviews
  • moderation
  • any store-specific features

Sync script

const BASE = "https://pwaregistry.org";

type Changes = {
  revision: number;
  added: string[];
  updated: string[];
  removed: string[];
};

export async function sync(localRevision: number) {
  const meta = await fetch(`${BASE}/registry/v1/meta.json`).then((r) => r.json());
  if (meta.revision === localRevision) {
    return { revision: localRevision, changed: false };
  }

  const changes = (await fetch(
    `${BASE}/registry/v1/changes.json?since=${localRevision}`,
  ).then((r) => r.json())) as Changes;

  for (const id of [...changes.added, ...changes.updated]) {
    const rec = await fetch(`${BASE}/registry/v1/apps/${id}.json`);
    if (rec.ok) await db.save(id, await rec.json());
  }
  for (const id of changes.removed) await db.markRemoved(id);

  return { revision: changes.revision, changed: true };
}

Run this on a schedule (hourly is enough). The browser never talks to PWARegistry on every page view.

First-time load

If localRevision is 0, download /registry/v1/index.json and then full records for the apps you will feature. After that, use the changes feed.

Render a store card

function StoreCard(app: {
  status: string;
  application: {
    name: string | null;
    description: string | null;
    icons: { primary: { src: string } | null };
    screenshots: { narrow: { src: string }[]; wide: { src: string }[] };
  };
}) {
  if (app.status === "REMOVED") return null;
  const icon = app.application.icons.primary;
  const shots =
    window.innerWidth < 768
      ? app.application.screenshots.narrow
      : app.application.screenshots.wide;
  return { icon: icon?.src, name: app.application.name, shots };
}

Narrow screenshots on mobile. Wide screenshots on desktop. Primary icon for the tile. Your ranking, featured row, and reviews stay in your database — PWARegistry will not provide them.

A smaller, category-only version is Build a Category Catalog.