Integrated Mode
In integrated mode, the host page handles EIP-712 signing on behalf of the widget via a postMessage bridge. The widget never shows a wallet UI. The user stays in the same wallet context they already have on the host page.
Quick start
1. Generate the embed snippet
Same as basic mode — use the widget builder to generate the iframe snippet.
2. Paste the snippet into your site
<iframe
id="omatrust-widget"
src="https://reputation.omatrust.org/widgets/reviews/embed?url=myapp.com&contract=0x1234...&chainId=8453&name=My+App"
width="400"
height="640"
style="border:0; width:100%; max-width:400px; background:transparent;"
loading="lazy"
title="OMATrust Review Widget"
></iframe>
3. Pass the user's wallet address
Since the host page already has the user's wallet, inject it into the iframe URL:
const iframe = document.getElementById("omatrust-widget");
const url = new URL(iframe.src);
url.searchParams.set("wallet", userWalletAddress);
iframe.src = url.toString();
4. Add the signing bridge
Install the SDK:
npm install @oma3/omatrust
Add the bridge to your page. The bridge listens for signing requests from the widget and forwards them to your app's wallet:
import { createSigningBridge } from "@oma3/omatrust/widgets";
const bridge = await createSigningBridge({
iframeId: "omatrust-widget",
signTypedData: async (domain, types, message) => {
// Replace this with your app's wallet signing call.
return await signer.signTypedData(domain, types, message);
},
});
The signTypedData callback is where you connect the bridge to your wallet library. Here are examples for common libraries:
Thirdweb
import { ethers6Adapter } from "thirdweb/adapters/ethers6";
const bridge = createSigningBridge({
iframeId: "omatrust-widget",
signTypedData: async (domain, types, message) => {
const signer = ethers6Adapter.signer.toEthers({ client, chain, account });
return await signer.signTypedData(domain, types, message);
},
});
wagmi / viem
import { useWalletClient } from "wagmi";
const { data: walletClient } = useWalletClient();
const bridge = createSigningBridge({
iframeId: "omatrust-widget",
signTypedData: async (domain, types, message) => {
return await walletClient.signTypedData({
domain,
types,
primaryType: "Attest",
message,
});
},
});
ethers v6
const bridge = createSigningBridge({
iframeId: "omatrust-widget",
signTypedData: async (domain, types, message) => {
return await signer.signTypedData(domain, types, message);
},
});
5. Clean up
Remove the bridge when the component unmounts or the page navigates away:
bridge.destroy();
6. User writes a review
- The widget loads and detects integrated mode (the bridge responds to the handshake)
- The widget uses the wallet address from the
walletquery param for the proof check - The user selects a rating and optionally writes review text
- The user clicks Sign and submit review
- The widget sends the EIP-712 typed data to the host via
postMessage - The bridge validates the request, then calls your
signTypedDatacallback - Your wallet prompts the user to approve the signature
- The bridge sends the signature back to the widget
- The widget submits the signed attestation to the relay server
- The widget shows the attestation UID and transaction hash
How mode detection works
The widget detects which mode to use automatically:
- On load, the widget sends
omatrust:readyto the parent window and retries at 500ms, 1s, and 2s - If the bridge responds with
omatrust:hostReadywithin 3 seconds, the widget uses integrated mode - If no response after 3 seconds, the widget falls back to basic mode
If your page creates the bridge before the iframe finishes loading, the bridge responds to omatrust:ready as soon as the widget sends it. No timing issues.
createSigningBridge API
function createSigningBridge(options: SigningBridgeOptions): SigningBridge;
Options
| Option | Type | Required | Description |
|---|---|---|---|
iframeId | string | Yes | The ID of the iframe element containing the widget. |
signTypedData | (domain, types, message) => Promise<string> | Yes | Callback to sign EIP-712 typed data. Must return the hex signature. |
devOriginOverride | string | No | Override origin for local dev (e.g., http://localhost:3000). In production, origin is derived from the OMA3 trust anchors. |
Return value
| Property | Type | Description |
|---|---|---|
destroy | () => void | Removes all event listeners. Call on cleanup. |