Skip to content
Help Center

Integrating Sentinel in web applications

View MarkdownContact support4 min read
On this page

This guide covers how to add the Persona Sentinel iframe to your webpage.

Setup

Ask your Persona Account team to set up a Sentinel transaction type and a client token before you start. You need both values to build the collection URL below.

Instructions

  1. Load the Sentinel collection URL.

    Embed a link to the Sentinel collection endpoint, with your client token and transaction type ID substituted as shown below.

    https://withpersona.com/sentinel?client-token={{CLIENT_TOKEN}}&transaction-type-id={{TXN_TYPE_ID}}&context={{CONTEXT}}&account-reference-id={{REFERENCE_ID}}&auto-create-account=true&auto-create-account-type-id={{ACCOUNT_TYPE_ID}}

    Here’s an overview of parameters. Note that two are optional:

    ParameterDescription
    contextRequired. A string that represents any contextual enrichment you’d like to provide for the event, such as onboardingEvent.
    account-reference-idRequired. A string parameter for including the user’s reference ID. Using this parameter ensures that information from the Sentinel event is synced to Graph, if you use it.
    auto-create-accountOptional. A boolean string (true or false) that controls whether an account is auto-created when one does not already exist for the given account-reference-id. Set to false to opt out of auto-creation; any other value is treated as true.
    auto-create-account-type-idOptional. An account type token (prefix acttp_) that specifies the account type to use when auto-creating an account. If omitted, defaults to the transaction type’s configured default account type.

    To verify this is working, visit the URL above. This should result in three network calls:

    • two calls to fp-us.withpersona.com for browser and device fingerprinting
    • one call to withpersona.com/api/sentinel/v1/transactions to create the Transaction

    A blank page should load. Inspect the page and check the Network tab to verify.

  2. Create the Transaction.

    To trigger Transaction creation, which sends the device information, context, and identifiers to Persona, post a message to the content window containing the sentinel page.

    If the page was opened directly in the main window, open the console and use:

    window.postMessage({ type: 'persona/passive/collect', origin: 'https://withpersona.com' })

    If the page is embedded within an iframe, use:

    document
      .getElementById('{{MY_IFRAME_ID}}')
      .contentWindow.postMessage(
        { type: 'persona/passive/collect', origin: '{{MY_ORIGIN}}' },
        'https://withpersona.com'
      )

Embed the Sentinel URL in an iframe, and only load the iframe and send the Transaction as needed.

import React, { useState, useRef, useMemo, useEffect } from 'https://esm.sh/react@18'
import ReactDOM from 'https://esm.sh/react-dom@18'

function SentinelContainer() {
  const [iframeLoaded, setIframeLoaded] = useState(false)
  const [sentinelCollecting, setSentinelCollecting] = useState(false)
  // To store the callback result from Sentinel
  const [postResult, setPostResult] = useState(null)
  const iframeRef = useRef(null)
  const buttonRef = useRef(null)
  const memoizedIframe = useMemo(
    () => (
      <iframe
        style={{ display: 'none' }}
        ref={iframeRef}
        id="sentinel"
        src="https://withpersona.com/sentinel?client-token={CLIENT_TOKEN}&transaction-type-id={TXN_TYPE_ID}&context=referenceImplementation&account-reference-id={REFERENCE_ID}"
      />
    ),
    []
  )

  const handleIframeLoad = () => {
    setIframeLoaded(true)
  }

  const handleMessage = (message) => {
    if (message.origin === 'https://withpersona.com') {
      setPostResult(message.data)
      setSentinelCollecting(false)
    }
  }

  useEffect(() => {
    // Add a message event listener to your application to handle postMessage callbacks
    window.addEventListener('message', handleMessage)
    const iframeElement = iframeRef.current
    if (iframeElement) {
      // Add a load event listener to the iframe to detect when it has finished loading
      iframeElement.addEventListener('load', handleIframeLoad)
    }
    // Return value is used to provide a cleanup function for React's useEffect
    return () => {
      window.removeEventListener('message', handleMessage)
      if (iframeElement) {
        iframeElement.removeEventListener('load', handleIframeLoad)
      }
    }
  }, [])

  const handleClick = () => {
    if (iframeRef.current && iframeRef.current.contentWindow) {
      setSentinelCollecting(true)
      // Post a message to the Sentinel iframe to begin collection
      iframeRef.current.contentWindow.postMessage(
        // The origin refers to the domain in which the iframe is being embedded
        { type: 'persona/passive/collect', origin: 'https://mywebpage.com' },
        // The second parameter is the target origin, this should be https://withpersona.com
        // (or the domain matching the Sentinel endpoint being used for the iframe)
        'https://withpersona.com/'
      )
    }
  }

  useEffect(() => {
    // Add a click event listener to the button that starts collection
    const buttonElement = buttonRef.current
    if (buttonElement) buttonElement.addEventListener('click', handleClick)
    return () => {
      if (buttonElement) buttonElement.removeEventListener('click', handleClick)
    }
  }, [])

  return (
    <>
      {memoizedIframe}
      <h1>Hello World</h1>
      <p>Iframe loaded: {iframeLoaded.toString()}</p>
      <p>Sentinel result: {sentinelCollecting ? 'Loading...' : ''}</p>
      <pre>{postResult ? JSON.stringify(postResult, null, 2) : 'No data available'}</pre>
      <button ref={buttonRef} disabled={!iframeLoaded || sentinelCollecting}>
        Click Me
      </button>
    </>
  )
}

// Tells React to attach the SentinelContainer component to the 'root' HTML div
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<SentinelContainer />)

Other parameters

Routing country

For end users and customers on the DE shard, taking advantage of geographical routing may be desired to reduce client-facing latencies. Since the /sentinel endpoint is fetched via a GET request when loaded via an iframe, you can specify an additional query string parameter:

https://withpersona.com/sentinel?client-token={{CLIENT_TOKEN}}&transaction-type-id={{TXN_TYPE_ID}}&routing-country=US

You can specify either US or DE for the routing-country query string parameter. Subsequent API calls made to Persona are routed accordingly.

This parameter primarily affects the Create Transaction API call. The initial /sentinel page load may still be served from a US-based server.

Was this page helpful?If something is missing, let us know and we will take a look.
Thanks for the feedback. It helps us improve these docs.