Embed the TOML Editor in your website
For developers: how to put the TOML Editor into your own page - in an iframe, in a window of its own or as a read-only viewer - and how documents, saves and AI results travel between the editor and your server. You need no sign-up and no key from us.
Any https page (and localhost) can embed the editor with an <iframe> and ?embed=1 - no sign-up, no key. Embedded, the editor hides the page text and shows a Save button. There are four ways to get the document in and out.
1. Open a file from a link, save to your server
src= opens a file (your server must allow CORS), webhook= makes "Save" (Ctrl+S) send the document to that address. Add &auto to save after every change.
<iframe src="https://toml.giit.ch/?embed=1&src=https://your-site.com/config/app.toml&webhook=https://your-site.com/save.php"
allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
The webhook gets a POST with JSON { editor: "toml", event: "save", id, name, content, updated }. A link carries no token (it would end up in server logs and the browser history), so a webhook in the address suits a save address that needs none, for example on localhost or in your intranet. For a public server, hand the webhook over with a token in tomleditor:load (hook: { url, token }) and check it, as this small PHP script does:
<?php
header('Access-Control-Allow-Origin: https://toml.giit.ch');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Methods: POST, OPTIONS');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') exit;
if (($_SERVER['HTTP_AUTHORIZATION'] ?? '') !== 'Bearer SECRET') { http_response_code(403); exit; }
$d = json_decode(file_get_contents('php://input'), true);
$name = preg_replace('/[^\w\- ]/u', '_', $d['name']);
file_put_contents(__DIR__ . "/config/$name.toml", $d['content']);
echo '{"ok":true}';
2. Your page holds the document (postMessage)
The editor says tomleditor:ready, your page answers with tomleditor:load, the editor reports tomleditor:loaded, tomleditor:change on real edits and tomleditor:save when the user saves. Your page may send tomleditor:get (the current state) or tomleditor:save (press Save). Saving then goes through your own login and session.
<iframe id="ed" src="https://toml.giit.ch/?embed=1" allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
<script>
const ed = document.getElementById('ed');
const ORIGIN = 'https://toml.giit.ch';
addEventListener('message', async e => {
if (e.source !== ed.contentWindow || e.origin !== ORIGIN) return;
const m = e.data;
if (m.type === 'tomleditor:ready') { // the editor is ready: hand it the document
ed.contentWindow.postMessage({
type: 'tomleditor:load',
name: 'Settings',
content: await (await fetch('/config/app.toml')).text()
}, ORIGIN);
}
if (m.type === 'tomleditor:change') document.title = '● not saved'; // a real edit
if (m.type === 'tomleditor:save') { // the user clicked "Save"
await fetch('/api/save', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: m.name, content: m.content }) });
document.title = 'Saved';
}
});
// A save button on your own page: the answer comes as tomleditor:save
function saveNow() { ed.contentWindow.postMessage({ type: 'tomleditor:get' }, ORIGIN); }
</script>
AI Assistant inside your page: it works in the frame too. With allow="clipboard-write" on the iframe, "Copy prompt" uses the clipboard directly (otherwise the editor falls back to the old copy command, or shows the prompt to copy by hand). A link the AI sends cannot reach an editor inside another website, so the editor tells the AI and the user to paste the AI's whole answer into the editor instead - or open the editor in a window of its own.
3. In a window of its own
window.open("https://toml.giit.ch/?embed=window", "tomleditor-17") opens the full editor in its own window and speaks the same messages with window.opener. Links from an AI reach it there. tomleditor:load may also carry context: { host, title, rules } - the AI prompt then says where the document belongs and follows your rules - and hook: { url, token }, a webhook for this document only that is never stored. Closing the window with unsaved changes sends tomleditor:closing.
4. AI through your own server
Hand the editor your own prompt, an address on your site and a key for this editor session. The AI dialog then shows "Connected to" your site, what you tell the AI, and the choice change the current document or make a new one; Copy prompt puts it all together. The AI posts its result with the key to your server, and your page opens it in the editor - a new document opens separately and stays in the user's browser. One key per editor session: it stays valid while the editor is open, and only while it has none the editor asks for it with tomleditor:key-request. The editor never sends the key itself and never stores it; the address must be https on your own host or a subdomain of it.
const key = async () => (await fetch('/api/ai-key.php?doc=17')).json(); // one key per editor session
const k = await key();
ed.contentWindow.postMessage({ type: 'tomleditor:load', name: 'Settings', content, ai: {
label: 'My Site', prompt: 'Keep every key and every comment.',
endpoint: 'https://your-site.com/api/ai-result.php', key: k.key } }, ORIGIN);
// remember the id from tomleditor:loaded and ignore change/save/closing with another id
// only while the editor has no key:
if (m.type === 'tomleditor:key-request') { const k = await key(); ed.contentWindow.postMessage({ type: 'tomleditor:ai', key: k.key }, ORIGIN); }
// while the editor is open, tell your server every minute; closing the editor or the page voids the key
setInterval(() => fetch('/api/ai-key.php?alive=' + k.key.slice(0, 8)), 60000);
// your server has a result (polling, SSE …): target is "current" or "new"
ed.contentWindow.postMessage({ type: 'tomleditor:load', name: 'Settings', content: draft, from: 'ai', target }, ORIGIN);
Make keys with at least 128 random bits, store only their hash, bind each to the logged-in user, the document and this editor session, make one per session, keep it valid only while your page reports the session as open, and void it when the editor or the page closes.
The whole protocol is in llms.txt - give it to an AI and it builds the connection for your system. The other giit editors work the same way with their own prefix - editors.giit.ch.
Show a document read-only (viewer)
?viewer=1 shows only the finished document: no code, no tools, nothing can be changed, and nothing is stored in the browser. The document comes from a link (#b64=, ?src=), from your page with tomleditor:load, or by POST as a normal form to post.php: the field content as text or b64 as base64, optionally name, at most 20 MB of text.
<form method="post" action="https://toml.giit.ch/post.php?viewer=1" target="_blank">
<input type="hidden" name="name" value="Report">
<input type="hidden" name="b64" value="…">
<button>Open</button>
</form>
Without viewer=1 the document opens in the normal editor. Either way it is kept in memory only: it is not stored on the server and does not join "My documents". Opened directly, the viewer says that the content comes from a third party.