On this page
Examples marked check on this site are compiled or validated automatically against the SDK's real types whenever the documentation is tested, so they stay in step with the code. Replace rvk_AAAAAAAAAAAAAAAAAAAAAAAA with the key from your portal.
1. Minimal#
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My agency</title>
</head>
<body>
<h1>Welcome</h1>
<script
src="https://recent-visit.com/widget/1/widget.js"
data-key="rvk_AAAAAAAAAAAAAAAAAAAAAAAA"
async
></script>
</body>
</html>2. Agency-specific configuration#
Everything comes from your key and your Widget Studio settings; you only add what you want to override. Here the page sets the launcher text and the assistant's name:
<script
src="https://recent-visit.com/widget/1/widget.js"
data-key="rvk_AAAAAAAAAAAAAAAAAAAAAAAA"
data-config='{"launcher":{"label":"Ask Alpha Treks"},"assistant":{"name":"Trek Buddy"},"welcomeMessage":"Namaste! Ask me about our treks and tours."}'
async
></script>3. Theme customisation#
<script
src="https://recent-visit.com/widget/1/widget.js"
data-key="rvk_AAAAAAAAAAAAAAAAAAAAAAAA"
data-config='{"appearance":"auto","theme":{"primary":"#7c2d12","accent":"#b45309","radius":20,"fontFamily":"\"Inter\", system-ui, sans-serif"},"themeDark":{"background":"#14110f"},"position":"left","offset":{"x":24,"y":24}}'
async
></script>The same in code, which is also how you change it while the page is running:
import { init } from '@recent-visits/widget'
const widget = init({ key: 'rvk_AAAAAAAAAAAAAAAAAAAAAAAA' })
widget.update({ theme: { primary: '#7c2d12', radius: 20 }, position: 'left' })4. Next.js (script tag, works today)#
Load the script once in your root layout:
import Script from 'next/script'
import type { ReactNode } from 'react'
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://recent-visit.com/widget/1/widget.js"
data-key={process.env.NEXT_PUBLIC_RECENT_VISITS_KEY}
strategy="afterInteractive"
/>
</body>
</html>
)
}5. React or Next.js with the package (once published)#
init needs the browser, so call it in an effect and clean up. It is safe under React strict mode (the effect runs twice in development; destroy makes the second init start fresh).
'use client'
import { useEffect } from 'react'
import { init } from '@recent-visits/widget'
export function RecentVisitsWidget({ tourSlug }: { tourSlug?: string }) {
useEffect(() => {
const widget = init({
key: process.env.NEXT_PUBLIC_RECENT_VISITS_KEY ?? '',
pageContext: tourSlug ? { tourSlug } : undefined,
})
return () => widget.destroy()
}, [tourSlug])
return null
}6. A tour page with context#
On a page about one of your tours, tell the widget which tour so suggestions fit it (the server accepts only your own published tours):
import { init } from '@recent-visits/widget'
const widget = init({ key: 'rvk_AAAAAAAAAAAAAAAAAAAAAAAA' })
widget.update({
pageContext: { tourSlug: 'poon-hill-5-days', title: 'Poon Hill trek, 5 days' },
notifications: {
enabled: true,
invitations: [{ text: 'Questions about this trek?', tourPage: true }],
},
})7. Headless quote request#
Build your own form and send the request through the client. Only send consent: true after the visitor has actually agreed to share their details with your agency. The request is created for your agency and arrives in Leads; the traveller's email and phone stay hidden from you until they accept a quote.
import { createClient, WidgetApiError } from '@recent-visits/widget'
const client = createClient({ key: 'rvk_AAAAAAAAAAAAAAAAAAAAAAAA' })
export async function sendQuote(form: {
name: string
email: string
message: string
agreed: boolean
}) {
if (!form.agreed) return { ok: false as const, reason: 'Please agree to share your details.' }
try {
await client.quote({
name: form.name,
email: form.email,
message: form.message,
consent: true,
tourSlug: 'poon-hill-5-days',
})
return { ok: true as const }
} catch (error) {
if (error instanceof WidgetApiError && error.code === 'rate_limited')
return { ok: false as const, reason: 'Too many requests. Please try again later.' }
return { ok: false as const, reason: 'Could not send your request. Please try again.' }
}
}Demo files#
The SDK repository includes runnable demo pages in apps/recent-visit-sdk/examples/ (index.html, themed.html, branding.html, server-branding.html). Serve the folder with any static server on a port whose domain you registered for Test (for example localhost) and put your Test key in the page.
Last checked against the product:
Related articles
- SDK installation · Install the Recent Visits widget with a script tag, add Subresource Integrity, run it locally, and understand the current npm status.
- SDK configuration reference · Every option the Recent Visits widget accepts: type, default, limits and an example. Invalid values are replaced by safe defaults.
- SDK API reference · The public surface of the Recent Visits widget package: init, the widget handle, the headless client, errors, types and the HTTP endpoints they use.
Still stuck? Contact us and tell us what you tried.