Docs
SDKs and tools

React components

Put an Agoo booking widget or visitor pre-registration form in your React or Next.js site, themed to match it.

Planned· P9For developers

This is designed and scheduled but not built yet. We document it now so you can plan your integration.

@ardent-africa/agoo-react gives you two components that run in your own pages: a booking widget for one of your booking types, and a pre-registration form that lets visitors register before they arrive. They use your organisation's branding from Agoo by default, and you can restyle them with CSS variables.

They work with a publishable key (agoo_pk_…), which is safe in the browser: it can only read your public booking types and the visitor types open for pre-registration, and create bookings and pre-registrations. It can't read visits, people, full forms or anything else.

Not using React? Use the embed script or the WordPress plugin instead.

Plan access

The components call the Agoo API directly from the browser, so live use follows API plan access: Pro and Enterprise. Test keys work on every plan. On other plans, use the embed script, which shows your hosted booking and pre-registration pages in a frame and works on every plan that has booking pages.

The install command will work once the package is published to npm.

Install

npm i @ardent-africa/agoo-react

Requires React 18.3 or 19. Import the stylesheet once, for example in your root layout:

import "@ardent-africa/agoo-react/styles.css"

Get a publishable key

An admin creates one in Console → Developers → API keys → Create key → Publishable. Use agoo_pk_test_… while you build: test bookings go to your test-mode sandbox and send no SMS, WhatsApp or email. Switch to agoo_pk_live_… when you go live.

Components

<AgooProvider>

Wrap the components in a provider once. It holds the key and loads your organisation's branding.

Prop

Type

<BookingWidget>

Shows available times for a booking type, collects the attendee's details and intake questions, and makes the booking. Agoo then sends the confirmation and reminders, and an in-person booking becomes an expected visit with a QR pass, exactly as from your own booking page. If the booking type requires the host's confirmation, the booking is a pending request until the host confirms it, and the widget tells the attendee so.

The intake questions come from the booking type's public_form in GET/booking-types: the questions asked of the visitor on its visit type's form, never the fields your staff fill in. Publishing a booking type makes these questions public, whether or not its visit type is open for pre-registration.

Prop

Type

<PreRegistrationForm>

Lets a visitor register before they arrive at a site to see a host you choose: who they are, and the custom questions your organisation asks for that visitor type. They get their QR pass by SMS, WhatsApp or email. If your organisation requires host approval, the host approves before the pass is sent.

The form fetches what it needs itself, with the publishable key, so there's nothing to configure in your code:

  1. It lists the visitor types open for pre-registration with GET/visit-types. A publishable key sees only types that are turned on and that an admin has opened for pre-registration in Console → Settings → Forms.
  2. It shows the chosen type's questions from its public_form: only the fields asked of the visitor, in the order and with the labels and help text set in the form builder. Fields your staff fill in, approval rules and watchlist settings are never sent to the browser.
  3. It checks the answers against that schema, then creates the pre-registration with POST/visits.

When an admin publishes a new version of the form, the component shows the new questions the next time it loads.

The host is set by your page

A publishable key can't list or search your people, so your staff directory can't be read from a web page. Set host to the person the visitor is coming to see, for example on a page for one person or one team. Without it, the component shows a message saying the form needs a host, and creates nothing. If visitors need to pick their host themselves, use the embed script: it shows your hosted pre-registration page, which has its own host search.

Prop

Type

What the callbacks receive

Because a publishable key can't read your data, the callbacks get a short summary, not the full object:

Types
type BookingSummary = {
  booking_id: string // booking_…
  status: "confirmed" | "pending" // pending: waiting for the host to confirm
  start_at: string // RFC 3339, UTC
  end_at: string
}

type PreRegistrationSummary = {
  visit_id: string // visit_…
  status: "expected" | "awaiting_approval"
  expected_at: string
}

To act on the full booking or visit on your server, listen for the booking.created or visit.created webhook rather than sending data from the browser.

Next.js App Router example

The components are interactive, so they must render in a Client Component. Keep the page itself a Server Component and import a small client wrapper:

app/book/booking.tsx
"use client"

import { useRouter } from "next/navigation"
import { AgooProvider, BookingWidget } from "@ardent-africa/agoo-react"

export function Booking() {
  const router = useRouter()

  return (
    <AgooProvider publishableKey={process.env.NEXT_PUBLIC_AGOO_PUBLISHABLE_KEY!}>
      <BookingWidget bookingType="btype_01jv4dk79q9g8xe6szaeavsntc" onBooked={(booking) => router.push(`/book/thanks?ref=${booking.booking_id}`)} />
    </AgooProvider>
  )
}
app/book/page.tsx
import { Booking } from "./booking"

export const metadata = { title: "Book a consultation" }

export default function Page() {
  return (
    <main>
      <h1>Book a consultation</h1>
      <Booking />
    </main>
  )
}
app/layout.tsx
import "@ardent-africa/agoo-react/styles.css"
import "./globals.css"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}
.env.local
NEXT_PUBLIC_AGOO_PUBLISHABLE_KEY=agoo_pk_test_…

Only the publishable key may have the NEXT_PUBLIC_ prefix. Never expose a secret key (agoo_sk_…) this way: anything prefixed NEXT_PUBLIC_ is sent to the browser.

Theming

By default the components use your organisation's branding from Agoo: the colours, logo and font you set in the console, with the same automatic contrast check. To fit them into your site's design, override these CSS variables on any parent element:

VariableControls
--agoo-color-primaryButtons, selected slots, links
--agoo-color-primary-foregroundText on primary-coloured elements
--agoo-color-backgroundComponent background
--agoo-color-foregroundMain text
--agoo-color-mutedSecondary text and unavailable slots
--agoo-color-borderBorders and dividers
--agoo-color-dangerError messages
--agoo-radiusCorner radius of buttons, inputs and cards
--agoo-font-familyFont for all text
globals.css
.booking-section {
  --agoo-color-primary: #0b5d4b;
  --agoo-color-primary-foreground: #ffffff;
  --agoo-radius: 6px;
  --agoo-font-family: inherit;
}

@media (prefers-color-scheme: dark) {
  .booking-section {
    --agoo-color-background: #111614;
    --agoo-color-foreground: #f2f5f4;
    --agoo-color-border: #2a332f;
  }
}

Variables you set win over your organisation's branding. If you choose colours yourself, check that text keeps a contrast ratio of at least 4.5:1 against its background.

Behaviour you get for free

  • Accessible. Keyboard navigation, visible focus, labelled fields and announced errors, designed to meet WCAG 2.2 AA.
  • Phone numbers. Ghana numbers can be typed as 024 123 4567 and are stored as +233241234567.
  • Time zones. Slots show in the booking type's time zone, with the visitor's own time alongside when they differ.
  • Privacy notice. The visitor sees your organisation's privacy notice before submitting, as on every Agoo page for visitors.
  • Double booking. If someone else takes a slot first, the widget explains and shows the next free times.

Content Security Policy

If your site sends a Content-Security-Policy header, allow the components to call the Agoo API:

Content-Security-Policy
connect-src 'self' https://api.agoo.ardent.africa;
img-src 'self' https://app.agoo.ardent.africa;

img-src is for your organisation's logo. The components don't load scripts or frames from other origins. The embed script needs a different policy.

On this page