Docs
Dashboard

Build an embedded app

View as Markdown

Build an embedded app

Build an embedded app when a feature belongs inside the Thor dashboard: for example, a product-review screen or a workflow that connects an external service. The React Router template provides the app shell, authentication routes, an authenticated Admin client, and a webhook endpoint.

Before you begin

Use the Thor React Router template and an app registration with a client ID, client secret, app URL, and scopes. Use a development project to install and exercise the app. The registration and runtime URL must refer to the same environment.

1. Configure the template

Create a working copy, then install from its directory:

Install
Code in bash

Set these values from your app registration:

VariablePurpose
THOR_APP_CLIENT_IDIdentifies the registered app
THOR_APP_CLIENT_SECRETServer-side app credential
THOR_APP_URLURL where the app is reachable
THOR_APP_SCOPESComma-separated scopes matching the app’s active version

The template example includes offline_access,products:view,channels:view. Request only the scopes your feature needs and keep the published app version and runtime configuration synchronized. Do not expose the client secret through a loader or browser bundle.

2. Run in the embedded context

Start the app
Code in bash

Use a reachable development URL when the dashboard needs to load the app. Keep that URL aligned with the app registration and authentication configuration. Open the installed app from the Thor dashboard so its embedded authentication flow can run. Opening an arbitrary app route outside that context is not a complete installation test.

3. Understand the starting files

FileResponsibility
app/thor.server.tsServer app configuration and exported authentication helpers
app/root.tsxApp provider, document shell, and dashboard appearance
app/routes.tsRoute registration
app/routes/home.tsxAuthenticated product-list example
app/api/auth.tsxAuthentication entrypoint
app/api/webhook-handler.tsxVerified webhook action
app/typesGenerated GraphQL types

Keep authentication in each protected route’s loader or action. Do not add another authenticate.admin(request) call to the root loader. See App authentication and sessions for why route ownership matters.

4. Build one feature

Follow Add a protected app page to query products through the authenticated Admin client. Preserve the template’s app provider, response headers, and error boundary integration. Keep dashboard appearance synchronized through the supplied appearance hook instead of forcing a fixed light theme.

Verify

Run pnpm typecheck and pnpm build. Test a fresh installation, a returning session, a missing permission, and an expired session. Before production, configure durable shared session storage and complete the deployment review in App authentication and sessions.