Integrate Outseta with Next.js

This guide walks you through integrating Outseta's authentication, profile management, and other embeds with a Next.js application. The key challenge with Next.js (and React apps in general) is ensuring the Outseta script loads before your components render.

For general React concepts, see our How to integrate Outseta with React guide.

Prerequisites

Before you begin, you'll need an Outseta account with at least one plan configured:

  1. Go to Billing > Plans and add at least one plan (can be a free plan to start)
  2. Go to Auth > Sign Up and Login and configure your sign up and login settings

If you'll be accepting payments, also connect Outseta to Stripe in Billing > Settings before going live.

Add the Outseta script

Use Next.js's Script component with strategy="beforeInteractive" to ensure Outseta loads before your app hydrates. This eliminates race conditions and the need for polling or MutationObservers.

⚠️ Important: Replace your-subdomain.outseta.com with your actual Outseta domain. You can find this in your Outseta account under Settings > General > Outseta URL.

For App Router (app/layout.js or app/layout.tsx):

import Script from 'next/script'

export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<Script id="outseta-config" strategy="beforeInteractive">
{`var o_options = {
domain: 'your-subdomain.outseta.com',
load: 'auth,customForm,emailList,leadCapture,nocode,profile,support',
monitorDom: true,
tokenStorage: 'cookie'
};`}
</Script>
<Script
src="https://cdn.outseta.com/outseta.min.js"
data-options="o_options"
strategy="beforeInteractive"
/>
</head>
<body>{children}</body>
</html>
)
}

For Pages Router (pages/_document.js or pages/_document.tsx):

import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'

export default function Document() {
return (
<Html>
<Head>
<Script id="outseta-config" strategy="beforeInteractive">
{`var o_options = {
domain: 'your-subdomain.outseta.com',
load: 'auth,customForm,emailList,leadCapture,nocode,profile,support',
monitorDom: true,
tokenStorage: 'cookie'
};`}
</Script>
<Script
src="https://cdn.outseta.com/outseta.min.js"
data-options="o_options"
strategy="beforeInteractive"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}

Notes on the options

load — Controls which Outseta modules are available. See the JavaScript configuration guide for all options.

⚠️ Warning: If you remove the nocode module from your configuration, you'll be responsible for capturing the access token, storing it, and managing auth state yourself. This is for advanced developers.

tokenStorage — Setting tokenStorage: 'cookie' stores the access token in a cookie, making it available during server-side rendering (SSR) and across browser tabs.

Choose your integration approach

You have two options for triggering Outseta embeds:

  • Data attributes — Simple setups, less code (requires monitorDom: true)
  • JavaScript API — Programmatic control

Data attributes

With DOM monitoring enabled, Outseta automatically detects elements with data attributes and attaches the appropriate functionality.

On-page embeds:

<!-- Profile (only visible when logged in) -->
<div data-o-profile="1" data-o-authenticated data-mode="embed"></div>

<!-- Login (only visible when logged out) -->
<div data-o-auth="1" data-o-anonymous data-mode="embed" data-widget-mode="login"></div>

<!-- Signup (only visible when logged out) -->
<div data-o-auth="1" data-o-anonymous data-mode="embed" data-widget-mode="register"></div>

Popup embeds:

<!-- Profile button (only visible when logged in) -->
<button data-o-profile="1" data-mode="popup">My Profile</button>

<!-- Login button (only visible when logged out) -->
<button data-o-auth="1" data-mode="popup" data-widget-mode="login">Login</button>

<!-- Signup button (only visible when logged out) -->
<button data-o-auth="1" data-mode="popup" data-widget-mode="register">Sign Up</button>

Log out:

<!-- Logout trigger (only visible when logged in) -->
<button data-o-authenticated data-o-logout-link="1">Logout</button>

The data-o-authenticated and data-o-anonymous attributes control visibility based on login state.

JavaScript API

For programmatic control, use the Outseta embed API methods.

On-page embeds:

// Render the profile embed into the element with id "profile-container"
Outseta.profile.open({ tab: 'profile', mode: 'embed', selector: '#profile-container' })

// Render the login embed into the element with id "login-container"
Outseta.auth.open({ widgetMode: 'login', mode: 'embed', selector: '#login-container' })

// Render the signup embed nto the element with id "login-container"
Outseta.auth.open({ widgetMode: 'register', mode: 'embed', selector: '#login-container' })

Popup embeds:

// Open profile popup
Outseta.profile.open({ tab: 'profile', mode: 'popup' })

// Open login popup
Outseta.auth.open({ widgetMode: 'login', mode: 'popup' })

// Open signup popup
Outseta.auth.open({ widgetMode: 'register', mode: 'popup' })

Log out:

// Log the user out
Outseta.logout()

See the full Embed API documentation for all available methods and events.

Access and update user information

Once a user is logged in, you can access their information client-side. The getUser() method returns a Promise that resolves when the user is logged in and their information has been retrieved from the server. The returned user object also has an update(data) method for updating user properties.

// Get the current user (returns a Promise)
const user = await Outseta.getUser()
console.log(user.Email, user.FirstName)

// Update user properties
await user.update({
FirstName: 'Jane',
LastName: 'Doe'
})

// Get the decoded JWT payload (synchronous)
const payload = Outseta.getJwtPayload()
console.log(payload.sub) // Person UID
console.log(payload['outseta:accountUid']) // Account UID

// Get the raw access token
const token = Outseta.getAccessToken()

For server-side verification, see Decode and verify Outseta JWT Access Tokens server-side.

Example repositories

For complete working examples, check out our React starter repositories:

Troubleshooting

Nothing's working

Make sure you've replaced your-subdomain.outseta.com with your actual Outseta domain. You can find this in Settings > General > Outseta URL.

Outseta is undefined

The script hasn't loaded yet. Ensure you're using strategy="beforeInteractive" on both Script tags.

Embeds don't appear on route changes

Make sure monitorDom: true is set in your configuration. This tells Outseta to watch for DOM changes, which is essential for single-page applications.

Data attributes not working

Two things are required for data attributes to work: the nocode module must be included in your load configuration, and monitorDom: true must be set. Check that both are present in your configuration.

Using AI tools

If you're using an AI coding assistant such as Lovable, Cursor, or Claude, use the "Copy as Markdown" button on this page and paste the entire document as context for it to work from.

If you have questions about integrating Outseta with Next.js, contact us at [email protected].