Introduction
What are App Extensions?
App Extensions let you embed a custom web page inside Fulcrum. When a user taps a button or field in your form, Fulcrum opens your HTML page in a full-screen panel, your page runs whatever logic you've built, and when it closes it can write data back into the form. Everything happens inside the Fulcrum mobile or web app — no browser switching, no external sign-ins.
You write the HTML, CSS, and JavaScript. Fulcrum handles opening the page, passing in the current form data, and receiving results back.
App Extensions work the same way on iOS, Android, and web.
Use Cases
- Custom UI for complex business logic (e.g., a QC dashboard that lets field crews flag issues on a schematic)
- Custom pickers not built into Fulcrum (image selection, advanced search, barcode workflows)
- Custom field types (SVG area selectors, range pickers, color ramps)
- Inspection summary interfaces (verifications, warning confirmations, sign-off screens)
- Charts and dashboards embedded inside a form
- Custom sub-forms (multi-step workflows that feel like a separate app)
How It Works
An App Extension has two parts that work together: a Data Event script attached to your Fulcrum form, and a custom HTML page that contains your extension's UI and logic.
The three steps
- Your Data Event calls
OPENEXTENSION()— This triggers the extension to open and passes in any data from the form (field values, record IDs, etc.) - Your HTML page receives the data and runs — The
Fulcrum.load()handler fires when the page is ready. Use it to set up your UI with the data passed in from the form. - Your page calls
Fulcrum.finish(data)— This closes the extension and sends results back to Fulcrum, where theonMessagehandler in your Data Event receives them and can write values back to your form.
Where the HTML file lives
Your HTML file can be hosted anywhere reachable by HTTPS, or stored as a Reference File directly on the form.
TipStoring your HTML as a Reference File using the attachment:// scheme lets the extension work offline. If you use an external HTTPS URL, the extension requires an internet connection.
NoteApp Extensions run in a sandboxed browser environment. This means you cannot save files locally to the device, generate downloadable images or PDFs, or access local device storage. Offline use is supported only for the page itself (via Reference Files) — not for API calls or dynamic data.
Quick Start
What you need
- A Fulcrum form with Data Events enabled
- Access to Reference Files (to store your HTML file on the form)
- A text editor or AI coding tool to write HTML/JavaScript
Step 1: Create your HTML file
Start with the template below. Copy it into a file named my-extension.html.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My Extension</title>
<!-- Required: Fulcrum extension script — do not modify -->
<script>(()=>{var s=(e,i)=>()=>(i||e((i={exports:{}}).exports,i),i.exports);var o=s((a,r)=>{var l=new URLSearchParams(location.search);function c(e){try{return JSON.parse(e)}catch(i){return null}}r.exports=window.Fulcrum={isExtension:l.get("extension")==="1",initialize:()=>{var i;let{params:e}=Fulcrum;Fulcrum.id=e==null?void 0:e.id,Fulcrum.url=e==null?void 0:e.url,Fulcrum.data=e==null?void 0:e.data,Fulcrum.origin=e==null?void 0:e.origin,(i=Fulcrum.onLoadOnce)==null||i.call(Fulcrum)},load:e=>{Fulcrum.onLoadOnce=()=>{Fulcrum.params&&!Fulcrum.isLoaded&&(Fulcrum.isLoaded=!0,e({data:Fulcrum.data}))},Fulcrum.onLoadOnce()},send:(e,{close:i=!1}={})=>{var u;e=e!=null?e:{};let n={id:Fulcrum.id,url:Fulcrum.url,data:e,close:i};(u=window.webkit)!=null&&u.messageHandlers?window.webkit.messageHandlers.extensionListener.postMessage(JSON.stringify(n)):window.parent&&window.parent.postMessage({extensionMessage:n},Fulcrum.origin)},receive:e=>{let i=c(e.data);i&&i.command==="initialize"&&!Fulcrum.params&&(Fulcrum.params=i.params,Fulcrum.initialize())},finish:e=>{Fulcrum.send(e,{close:!0})}};Fulcrum.isExtension?window.addEventListener("message",Fulcrum.receive,!1):window.addEventListener("DOMContentLoaded",Fulcrum.initialize)});o();})();</script>
<script>
// Called when the extension opens — data contains values passed from the form
Fulcrum.load(({ data }) => {
document.getElementById('greeting').textContent = 'Hello, ' + (data.name || 'World') + '!';
});
function done() {
// Pass results back to the form and close the extension
Fulcrum.finish({ result: 'Done!' });
}
</script>
</head>
<body>
<h1 id="greeting">Loading...</h1>
<button onclick="done()">Submit</button>
</body>
</html>Step 2: Upload the file to your form
- In the Fulcrum form builder, open Reference Files
- Upload your
my-extension.htmlfile - Note the filename exactly — you'll reference it in your Data Event as
attachment://my-extension.html
Step 3: Add a Data Event to open the extension
In your form's Data Events editor, add a script that calls OPENEXTENSION(). This example triggers the extension when a button field named launch_tool is tapped:
ON('click', 'launch_tool', () => {
OPENEXTENSION({
url: 'attachment://my-extension.html',
title: 'My Extension',
data: {
// Pass any form values into the extension
name: $inspector_name,
record_id: RECORDID(),
},
onMessage: ({ data }) => {
// Write results back to form fields
SETVALUE('result_field', data.result);
}
});
});
TipAny Fulcrum field value, record metadata, or calculation result can be passed in the data object. The extension receives it as a plain JavaScript object.
Building with AI
App Extensions are well-suited to AI-assisted development (sometimes called "vibe coding"). You can describe what you want to a tool like Claude, ChatGPT, or Gemini, and have it generate the HTML, CSS, and JavaScript for your extension.
What to give your AI tool
For best results, include the following in your prompt:
- The starter template above — paste it in so the AI understands the Fulcrum extension API structure
- What data you're passing in — list the field names and types from your
dataobject - What the UI should do — describe the interaction: what the user sees, what they do, what gets sent back
- What gets sent back — describe the structure of what
Fulcrum.finish()should return
Example prompt
Here's a starting-point prompt you can adapt:
I'm building a Fulcrum App Extension. Here is the starter HTML template:
[paste template]
My extension should:
- Show a list of the items passed in via data.items (each has a name and status)
- Let the user mark each item as pass/fail with a button
- When the user taps Done, call Fulcrum.finish() with an array of
{name, status} objects reflecting their selectionsKeep it simple — plain HTML, no build step, no external libraries.
App Extension API Reference
Including the Fulcrum extension script in your HTML provides the following API. You can also use the npm package fulcrum-extensions as an alternative.
Fulcrum.load(callback)
Called when the extension page has loaded and is ready to receive data from Fulcrum.
Fulcrum.load(({ data }) => {
// data equals the object passed from OPENEXTENSION({ data: {...} })
// Use this to initialize your UI with existing form values
});- Called once per extension session, after the page finishes loading
- The data argument is the plain object you passed into
OPENEXTENSION({ data: {...} }) - Use this to pre-populate your UI with existing form values when the user is editing a record
Fulcrum.finish(data)
Closes the extension and sends results back to the onMessage handler in your Data Event.
Fulcrum.finish({
// Return any data you want to write back to the form
field_value: 'some result',
score: 42,
});- Call this when the user is done — it closes the extension panel
- The object you pass is available as data inside the
onMessagecallback in your Data Event - Calling
Fulcrum.finish()with no argument closes the extension without sending any data back
OPENEXTENSION() — Data Events
Called from your Data Event script to open an App Extension. See the OPENEXTENSION reference for full parameter documentation.
OPENEXTENSION({
url: 'attachment://my-extension.html', // or any HTTPS URL
title: 'My Extension', // shown in the panel header
data: { /* any data to pass in */ },
onMessage: ({ data }) => {
// called when Fulcrum.finish(data) is called in your HTML
}
});Known Limitations
App Extensions run in a sandboxed browser environment. The following capabilities are not supported:
File and photo access
- You cannot save files or images to the device from within an extension
- You cannot generate downloadable raster images (PNG, JPEG, PDF)
- Photos from Fulcrum photo fields must be fetched via the Fulcrum API (HTTPS) — there is no direct local access
Offline limitations
- Using the Fulcrum API inside your extension (e.g., to fetch choice lists or photos) requires an internet connection, even if the HTML page itself is stored offline as a Reference File
- Choice lists managed in Fulcrum must be fetched via the API and cannot be accessed locally
Hardware connectivity
- HTTP-based hardware protocols (e.g., 360-degree cameras that communicate over local Wi-Fi via HTTP) do not work in the sandboxed HTTPS environment
- Bluetooth device support is not currently available in App Extensions
State persistence
- Extensions open to a fresh state each time — data from a previous session is not automatically restored
- To preserve state across sessions, write data back to a Fulcrum form field via
Fulcrum.finish()and pass it back in on the next open via the data parameter
Examples
The following examples are available in the Examples section of the docs: