Skip to main content
Your page owns everything under its own path. tap.nav.push moves inside it, useTapParams() reads the segments, and tap.nav.setSearch keeps a selection in the URL so a link reopens what the owner was looking at.

What the segments look like

useTapParams() hands back the sub-path split for you, keyed by position. There are no named parameters, because your page declares no route pattern for the host to match. On /projects/prj_1/ext/funnel-lab/explore/funnels/123 that is { pageId: "explore", path: "funnels/123", "0": "funnels", "1": "123" }.

Where you can go

A path that starts with /projects/ is taken as written; anything else is resolved under /projects/:projectId/ext/:extensionId, which is why the sample above begins with the page id. A target outside the current project does not navigate: the owner gets a toast naming your extension, and the page stays where it was. Those five calls are the whole of navigation. The host owns the router, which is what keeps a failing extension from taking the page with it.

Leaving Tappify

openExternal is the only way out, and the host draws the exit itself: a confirmation naming your extension and the URL, then a new tab. The expand panel’s footer carries the same exit, labelled with your extension’s name. Two other escapes exist for the same reason — your code cannot reach the host’s DOM:
Both run in the host’s own document, so a download from your widget lands where every other Tappify download lands, and a copy confirms with a toast.