Skip to content
decebal edited this page Apr 22, 2026 · 1 revision

Integrating the iProov Web SDK with Next.js requires a dynamic import because the SDK accesses browser APIs (window, document) that are not available during server-side rendering.

This guide covers Next.js with the Pages Router. The same dynamic import pattern applies to the App Router.

Integration

The key difference from a standard React integration is that @iproov/web-sdk must be imported dynamically inside a useEffect hook (or equivalent client-side lifecycle), not at the top of the file.

pages/index.tsx

import Head from "next/head"
import { useEffect, useState } from "react"

function IProovMe() {
  const [token, setToken] = useState(null)
  const [isLoading, setLoading] = useState(true)

  useEffect(() => {
    const fetchIproovMe = async () => {
      // Dynamic import is required because Next.js renders on the server first,
      // and the iProov SDK requires browser APIs (window, document) to initialise.
      return await import("@iproov/web-sdk")
    }

    const fetchToken = async () => {
      await fetchIproovMe()

      // Replace with your backend token endpoint
      const response = await fetch("***YOUR_BACKEND_TOKEN_ENDPOINT***", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          resource: "https://iproov.app",
          user_id: "example@example.com",
          client: "Web SDK NextJS",
        }),
      })
      const data = await response.json()
      setToken(data.token)
      setLoading(false)
    }

    fetchToken().catch((err) => {
      setLoading(false)
      console.error(err)
    })
  }, [])

  if (isLoading) return <p>Loading...</p>
  if (!token) return <p>Error loading token</p>

  return (
    <iproov-me
      token={token}
      base_url="***YOUR_BASE_URL***"
      assets_url="***YOUR_ASSETS_URL***"
      aria_live="assertive"
    >
      <div slot="start">
        <div>Preparing verification...</div>
      </div>
    </iproov-me>
  )
}

export default function Home() {
  return (
    <>
      <Head>
        <title>iProov Web SDK - Next.js</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </Head>
      <main>
        <IProovMe />
      </main>
    </>
  )
}

Why Dynamic Import?

Next.js pre-renders pages on the server by default. The iProov Web SDK registers a custom element (<iproov-me>) and accesses browser-only APIs during initialisation. A static import "@iproov/web-sdk" at the top of the file would execute during SSR and fail.

By using await import("@iproov/web-sdk") inside useEffect, the SDK is only loaded client-side after the component has mounted.

Support Checker

After the dynamic import, the Support Checker is available via window.IProov.IProovSupport:

useEffect(() => {
  const init = async () => {
    await import("@iproov/web-sdk")
    const supportChecker = new window.IProov.IProovSupport()
    const { supported, granted } = await supportChecker.check()
    console.log("Supported:", supported, "Granted:", granted)
  }
  init()
}, [])

See the full Support Checker documentation.

Custom Slots

Pass custom slots as children of the <iproov-me> component:

<iproov-me token={token} base_url="***YOUR_BASE_URL***" assets_url="***YOUR_ASSETS_URL***">
  <div slot="ready">Ready to scan</div>
  <div slot="button">Start scanning</div>
  <div slot="passed">Verification passed!</div>
  <div slot="failed">Verification failed</div>
</iproov-me>

Next.js Configuration

next.config.js

const nextConfig = {
  reactStrictMode: true,
}

module.exports = nextConfig

No special Next.js configuration is required beyond the standard setup. The dynamic import handles the SSR/client boundary.

Assets

Set the assets_url attribute to the URL where your application serves the iProov SDK assets. For Next.js, copy the required assets from node_modules/@iproov/web-sdk into your public/ directory and set assets_url to your application's origin. See the Serving Assets and CORS guide for details.

HTTPS in Development

The iProov SDK requires HTTPS for camera access. For local development with Next.js, you can use a custom server with SSL certificates:

server.js

const { createServer } = require("https")
const { parse } = require("url")
const next = require("next")
const fs = require("fs")

const dev = process.env.NODE_ENV !== "production"
const app = next({ dev })
const handle = app.getRequestHandler()

const httpsOptions = {
  key: fs.readFileSync("path/to/your/dev.key"),
  cert: fs.readFileSync("path/to/your/dev.crt"),
}

app.prepare().then(() => {
  createServer(httpsOptions, (req, res) => {
    const parsedUrl = parse(req.url, true)
    handle(req, res, parsedUrl)
  }).listen(3000, (err) => {
    if (err) throw err
    console.log("> Secure server started on https://localhost:3000")
  })
})

Clone this wiki locally