Skip to main content

Related-application discovery

Use this recipe only when the product already owns a native or installed-web companion and has completed that platform's bidirectional verification. The getInstalledRelatedApps() API is experimental, limited to top-level secure contexts in supporting browsers, and intended here only to avoid redundant presentation such as a companion-app onboarding banner.

Manifest and verification

The starter omits both members. Add the verified listing while leaving native preference false:

{
"prefer_related_applications": false,
"related_applications": [
{
"platform": "play",
"id": "com.example.companion",
"url": "https://play.google.com/store/apps/details?id=com.example.companion"
}
]
}

Do not invent identifiers. Android requires Digital Asset Links; Windows, cross-scope PWAs, and other platforms have their own verification mechanisms. Manifest declaration alone is not proof of ownership. Keep prefer_related_applications false or omitted so Chromium retains PWA installability.

Presentation-only discovery

import { discoverRelatedApplications } from "@nzip/lofi/recipes/related-app-discovery";

const discovery = await discoverRelatedApplications({
allow: [{
platform: "play",
id: "com.example.companion",
url: "https://play.google.com/store/apps/details?id=com.example.companion",
}],
});

const showCompanionOnboarding = discovery.status !== "installed";

Only exact allow-list matches are returned. Browser-supplied versions, unknown apps, and extra fields are discarded. Unsupported, empty, malformed, embedded-context, and rejected calls all retain the normal PWA experience. Never use discovery for authentication, authorization, account linking, feature entitlements, or proof that the current user controls the companion app.

Test unsupported and empty results, exact and mismatched platform IDs/URLs, API rejection, top-level versus embedded contexts, privacy-safe UI, PWA installability, platform verification updates, and removing the manifest listing.