Skip to main content

Put your agent in your site

The app you build in the Studio (the agent and its own interface) can live inside any site: WordPress, Shopify, Wix or your own.

1. Publish it​

In the Studio: your agent → Project → Deployment → Publish. The app gets its address, for example https://my-shop-8c84.digitorn.app. Project → Embed then gives you every code below, already filled in.

2. Show it in your page​

html
<iframe
src="https://my-shop-8c84.digitorn.app"
style="width:100%;height:640px;border:0;border-radius:12px"
allow="clipboard-write; microphone">
</iframe>

That's enough for visitors: each browser is a guest, who finds their conversations again on the same browser. Publish again after a change and every page that embeds the app shows the new version.

3. Recognize your users​

When your user is signed in to your site, open the app already signed in as them, with your own id for them. Their conversations, their plan and the accounts they connected (their Gmail, their calendar…) then follow them on every device: same id, same person.

text
 Your user's browser            Your server                              Digitorn
1. opens /assistant ────────▶ 2. reads YOUR session: user_482
3. POST /v1/users/user_482/launch ─────▶ 4. checks sk_, finds or
(sk_ from its environment) creates user_482, issues a
ticket (once, 2 minutes)
5. gets { url } ◀───────────────────────
6. gets the page with ◀─────── puts url in the iframe src
<iframe src="url">
7. the iframe opens ──────────────────────────────────────────────────▶ 8. trades the ticket for a
session as user_482

Four rules:

  1. The id comes from your own session, never from the URL or anything the browser sends. Otherwise anyone could open anyone's account (/assistant?user=someone-else).
  2. The secret key stays on your server, in its environment.
  3. A new link for every page view: each one works once.
  4. A stable id: the same user keeps the same id for life (their id in your database, not a session id or an e-mail that may change).

Your server asks for a link each time it shows the page:

js
// Node / Express: the user signed in to YOUR site
app.get("/assistant", requireLogin, async (req, res) => {
const user = req.session.user; // from your session, never from the URL

const r = await fetch(`https://api.digitorn.ai/v1/users/${encodeURIComponent(user.id)}/launch`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DIGITORN_SECRET_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ name: user.name, email: user.email }),
});
if (!r.ok) return res.status(502).send("Assistant unavailable");
const { url } = await r.json(); // works once, for 2 minutes

res.render("assistant", { assistantUrl: url }); // <iframe src="<%= assistantUrl %>">
});
php
<?php // PHP: the user signed in to YOUR site
$user = $_SESSION['user']; // from your session, never from the URL
$ch = curl_init('https://api.digitorn.ai/v1/users/' . rawurlencode($user['id']) . '/launch');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('DIGITORN_SECRET_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['name' => $user['name'], 'email' => $user['email']]),
]);
$url = json_decode(curl_exec($ch), true)['url'];
?>
<iframe src="<?= htmlspecialchars($url) ?>" style="width:100%;height:640px;border:0"></iframe>
json
{
"url": "https://my-shop-8c84.digitorn.app/#digitorn_signin=Qd…",
"fragment": "#digitorn_signin=Qd…",
"expires_at": "2026-10-11T10:42:00Z",
"user": { "id": "user_482", "name": "Aïcha Koné", "created": true }
}
  • The link works once, within 2 minutes: ask for a new one each time you render the page. The app then keeps the user signed in.
  • The ticket travels after #: browsers never send that part to any server, so it never appears in a log or a Referer.
  • name and email are optional and update the user's profile.
  • To open the app at another of your allowed sites (a custom domain), pass "app_url": "https://chat.myshop.com/". Only the project's allowed sites (Project → Access) are accepted.
  • A user who signed up by themselves in the app, or a disabled user, can never be opened this way (user_conflict, user_disabled).
  • url is in the answer once the app is published (or when you pass app_url); before that you only get fragment.
  • Errors: 401 invalid or revoked key, 403 server_only (called from a browser) or user_disabled, 409 user_conflict, 422 invalid id or app_url_not_allowed, 429 too many requests.

4. Tell the agent more​

Your page can tell the agent what it should know about the moment: the page, the cart, an order. Send it again whenever it changes.

html
<script>
const agent = document.querySelector("iframe");
const send = () => agent.contentWindow.postMessage({
type: "digitorn:context",
page: { title: document.title, url: location.href },
data: { cart: "2 bags of rice 25 kg", total: "36 000 FCFA" }
}, "https://my-shop-8c84.digitorn.app");
// The app says "digitorn:ready" once it listens; send then (and on load).
window.addEventListener("message", (e) => {
if (e.source === agent.contentWindow && e.data?.type === "digitorn:ready") send();
});
agent.addEventListener("load", send);
</script>

Call send() again whenever the page or the cart changes.

The agent sees it as declared by your site, not as a verified identity: it greets "Aïcha" and talks about her cart. Anyone can change what a page sends (browser tools), so never put a right in it (a tier, a discount, a role). Facts that matter go through your server: the link of step 3 for who she is, and claims for what you vouch for. When both say something, the agent trusts the server.

Without an iframe​

Building your own interface? Talk to the agent from your server with the conversations API, or use the @digitornai/sdk React package in your web app.