Plain HTML and other single-page apps
Add a Web Agent to a site that has no framework, or to an app built with SolidJS, Preact or Alpine.js. The loader is plain JavaScript with no framework dependency, so the install is the same everywhere: a script tag, or the npm package where the app has a bundler. At the end, the agent's launcher is on your pages and the agent knows which user is signed in.
Prerequisites
- A page you can add a script tag to, or an app with a bundler.
- A Web Agent in your workspace whose analysis has finished, with a version deployed to Production.
1. Copy your snippet
- In the portal, go to Web Agents and select your agent.
- In the Overview tab, find the Install the assistant card and select the JS / Manual tab.
- Select Copy.
2. Add the script tags
Paste the snippet into every page, before </body>. On a site with a shared layout or template, paste it there once.
<script src="https://webagent.faustine.ai/loader.js"></script>
<script>
Faustine.init({ agentId: '<AGENT_ID>' });
</script>The first tag defines window.Faustine. The second starts the agent. init loads the Production environment. To load another one, pass its name: env: 'Staging'.
If the site has no signed-in users, the JS / Auto tab has a shorter snippet that starts the widget by itself. See Install with a script tag.
3. Identify the signed-in user
Call Faustine.identify when the page knows who the user is. This example asks your backend and passes a display name and email, which appear in the agent's Monitoring tab as Unverified.
<script src="https://webagent.faustine.ai/loader.js"></script>
<script>
Faustine.init({ agentId: '<AGENT_ID>' });
fetch('/api/me')
.then((res) => (res.ok ? res.json() : null))
.then((me) => {
if (me) {
Faustine.identify({ userId: me.id, name: me.name, email: me.email });
}
});
</script>/api/me stands for your own endpoint that returns the signed-in user. On a page your server renders, you can write the values into the call instead of fetching them.
In your sign-out handler, call Faustine.logout() before you leave the page. It removes the identity and the open conversation from the browser.
For production, replace the labels with a token signed by your backend. See Verify your users with a signed token.
4. Open your site
Load a page that has the snippet.
Checkpoint
The agent's launcher appears on the page. Select it and send a message. In the portal, the conversation appears under the agent's Monitoring tab.
Install from npm in SolidJS or Preact
In an app with a bundler, install the package and start the agent from a module. The calls are the same as with the script tag, and they are typed.
npm install @faustine-ai/web-agentpnpm add @faustine-ai/web-agentyarn add @faustine-ai/web-agentbun add @faustine-ai/web-agentimport Faustine from '@faustine-ai/web-agent';
export const agent = Faustine.init({
agentId: '<AGENT_ID>',
});Import the module from the entry file, and identify the user from the root component. useSession stands for your own session code.
import { render } from 'solid-js/web';
import App from './App';
import './faustine';
render(() => <App />, document.getElementById('root')!);user is a signal. The effect runs again each time it changes.
import { createEffect } from 'solid-js';
import { agent } from './faustine';
import { useSession } from './session';
export default function App() {
const { user } = useSession();
let signedIn = false;
createEffect(() => {
const current = user();
if (current) {
agent.identify({ userId: current.id, name: current.name, email: current.email });
signedIn = true;
} else if (signedIn) {
agent.logout();
signedIn = false;
}
});
return <main>Your app</main>;
}import { render } from 'preact';
import { App } from './App';
import './faustine';
render(<App />, document.getElementById('app')!);user is a value. The effect runs again when it changes between renders.
import { useEffect, useRef } from 'preact/hooks';
import { agent } from './faustine';
import { useSession } from './session';
export function App() {
const { user } = useSession();
const signedIn = useRef(false);
useEffect(() => {
if (user) {
agent.identify({ userId: user.id, name: user.name, email: user.email });
signedIn.current = true;
} else if (signedIn.current) {
agent.logout();
signedIn.current = false;
}
}, [user]);
return <main>Your app</main>;
}Both examples call logout only after a user has been identified, so a visitor who never signs in keeps their conversation.
Call the agent from Alpine.js
An Alpine.js site uses the script tags of step 2. Faustine is a global, so an Alpine expression can call it. This button opens and closes the agent's panel.
<button type="button" x-data @click="Faustine.toggle()">Help</button>To replace the agent's launcher with a button like this one, see Use your own launcher button.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Faustine is not defined in the console |
The loader tag has async or defer, or the inline script comes before it. |
Load loader.js with a plain script tag, before the script that calls Faustine.init. |
No launcher, and the request to webagent.faustine.ai/embed returns 404 |
No environment of the agent serves a version. | Publish a version. |
No launcher, and the same request returns 403 |
The page's domain is not in the environment's allowed domains. | See Restrict the domains that can load the agent. |
| The user stays anonymous on a page with the JS / Auto tag | Faustine.identify needs Faustine.init, which that tag does not call. |
Use the JS / Manual snippet. |
Next steps
- Verify your users with a signed token: give users their history on every device.
- Restrict the domains that can load the agent: allow your own domains only.
- Install with a script tag: the two script-tag snippets and when to use each.
- JavaScript API: every option of
initand every method of the handle.
Last updated November 13, 2026