-
Notifications
You must be signed in to change notification settings - Fork 9
NextJS
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.
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>
</>
)
}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.
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.
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.config.js
const nextConfig = {
reactStrictMode: true,
}
module.exports = nextConfigNo special Next.js configuration is required beyond the standard setup. The dynamic import handles the SSR/client boundary.
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.
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")
})
})