Native Host Requirements for Implementing the UCP Embedded Protocol
Native hosts must inject global JavaScript objects named Embedded{Capability}ProtocolConsumer and Embedded{Capability}Protocol into the web-view context to enable JSON-RPC 2.0 message exchange between the host application and embedded business UIs.
The Universal-Commerce-Protocol (UCP) Embedded Protocol defines how native applications—such as iOS/Android apps or desktop clients—host business UIs within web-views while maintaining secure, bidirectional communication. According to the specification in docs/specification/embedded-protocol.md, native hosts must implement a specific bridging layer that exposes standardized global objects to the embedded JavaScript context. This article details the mandatory technical requirements for building a compliant native host implementation.
Mandatory Bridging Layer Components
Native hosts must provide two distinct global JavaScript objects that serve as the communication bridge between the host runtime and the embedded business UI.
Consumer Object Injection
The host must inject a consumer object into the iframe or web-view before the business UI loads. According to docs/specification/embedded-protocol.md, this object must be named following the pattern window.Embedded{Capability}ProtocolConsumer (recommended) or window.webkit.messageHandlers.Embedded{Capability}ProtocolConsumer for WebKit-based environments.
The consumer object must implement a single method:
postMessage(message: string): void– Accepts a JSON-stringified JSON-RPC 2.0 request that the host parses and acts upon.
For example, the Checkout capability requires EmbeddedCheckoutProtocolConsumer, while the Cart capability uses EmbeddedCartProtocolConsumer as defined in embedded-checkout.md and embedded-cart.md respectively.
Producer Object Exposure
The host must also expose a producer object that allows the native side to send messages back to the embedded context. The host injects JavaScript that calls window.Embedded{Capability}Protocol.postMessage(jsonMessage), where the embedded context listens for these calls immediately upon loading.
Handshake Timing and Message Flow
Proper initialization sequencing is critical for protocol compliance.
Ready Handshake Requirements
As specified in the Native Hosts section of embedded-protocol.md, the host must complete the following steps before the embedded context loads:
- Register the global consumer and producer objects in the JavaScript context.
- Prepare to receive the initial
readyrequest (method nameec.readyfor checkout contexts). - Validate the incoming handshake and reply with a JSON-RPC response containing the matching
id.
The embedded UI broadcasts its ready request immediately upon loading. If the global objects are not present, the handshake fails, preventing subsequent communication.
Message Format Compliance
All messages exchanged via the injected globals must conform to the JSON-RPC 2.0 envelope defined in the Message Format section of the specification. Each message must include:
"jsonrpc": "2.0""method"– The procedure name being invoked."params"– Arguments for the method."id"– Optional for notifications, required for requests.
The host must parse the JSON string, validate the envelope structure, and reply with matching id values for requests.
Security and Error Handling Constraints
Native implementations must enforce strict security policies and standardized error responses.
Origin Validation
As documented in the Security section of embedded-protocol.md, hosts utilizing postMessage-based bridges must validate the origin of all incoming postMessage calls. Failure to validate origins constitutes a security_error. The bridge must not be exposed to untrusted frames or contexts outside the UCP ecosystem.
Error Response Standards
Transport-level failures—such as malformed JSON or unknown methods—must return using the JSON-RPC error field. Application-level errors must be wrapped within the result.ucp.status payload. This dual-layer error model ensures consistent error handling across native and web host implementations.
Capability-Specific Naming Conventions
Each UCP capability defines exact global names that native hosts must implement:
- Checkout:
EmbeddedCheckoutProtocolConsumer/EmbeddedCheckoutProtocol - Cart:
EmbeddedCartProtocolConsumer/EmbeddedCartProtocol
The capability-specific bindings in docs/specification/embedded-checkout.md and docs/specification/embedded-cart.md define the exact method contracts and event sequences for each context. The OpenRPC schema at source/services/shopping/embedded.openrpc.json provides the complete method definitions useful for code generation and validation.
Implementation Examples
iOS WKWebView Consumer Injection
When implementing a host using iOS WKWebView, inject the consumer object before loading the business UI:
// Swift → WKUserContentController injection
let script = """
window.EmbeddedCheckoutProtocolConsumer = {
postMessage: function(message) {
// Forward the JSON-RPC string to the native layer
window.webkit.messageHandlers.checkoutConsumer.postMessage(message);
}
};
"""
webView.evaluateJavaScript(script, completionHandler: nil)
Native Message Handler
The following Python pseudocode demonstrates handling incoming EP messages and responding via the producer bridge:
def handle_checkout_message(json_str: str):
msg = json.loads(json_str) # Parse JSON-RPC envelope
assert msg["jsonrpc"] == "2.0"
method = msg["method"]
if method == "ec.ready":
# Process handshake, return optional upgrade or credentials
response = {
"jsonrpc": "2.0",
"id": msg.get("id"),
"result": {
"ucp": {"version": "1.0", "status": "success"},
# ... additional fields ...
}
}
# Send back via the producer bridge
webview.evaluate_javascript(
f'window.EmbeddedCheckoutProtocol.postMessage({json.dumps(response)})')
Host-to-Embedded Notifications
After the ready handshake succeeds, the host can send state updates to the embedded context:
// Host-initiated notification
const notification = {
jsonrpc: "2.0",
method: "ec.start",
params: {
checkout: { /* current checkout state */ }
}
};
window.EmbeddedCheckoutProtocol.postMessage(JSON.stringify(notification));
Summary
- Native hosts must inject
Embedded{Capability}ProtocolConsumer(for incoming messages) andEmbedded{Capability}Protocol(for outgoing messages) before the embedded UI loads. - All messages must use JSON-RPC 2.0 envelopes with proper
jsonrpc,method,params, and optionalidfields. - The host must handle the
ec.readyhandshake immediately upon receiving it from the embedded context. - Security requires origin validation on all
postMessagecalls to prevent exposure to untrusted frames. - Transport errors use the JSON-RPC
errorfield; application errors useresult.ucp.status. - Capability-specific bindings in
embedded-checkout.mdandembedded-cart.mddefine exact global names likeEmbeddedCheckoutProtocolConsumer.
Frequently Asked Questions
What happens if the host injects the global objects after the embedded UI loads?
The embedded business UI sends its ready request immediately upon loading. If window.Embedded{Capability}ProtocolConsumer is not present, the request fails, the handshake never completes, and the embedded UI remains in a non-functional state. According to embedded-protocol.md, hosts must register these globals before loading the web-view content.
Can native hosts use MessageChannel instead of injected globals?
Yes, after the initial handshake completes, hosts may upgrade to a MessageChannel for subsequent communication. However, the host must still provide the initial bridging layer via injected globals to handle the ready request and establish the session. The specification allows for transport upgrades but requires the global object bridge for initialization.
How should native hosts handle session errors?
When receiving error or session_error notifications via the consumer object, the host must tear down the embedded web-view and optionally redirect the buyer using the continue_url provided in the error payload. This ensures secure session termination and proper buyer experience flow as defined in the Response Handling section of the specification.
Where can developers find the complete method definitions for code generation?
Developers should reference source/services/shopping/embedded.openrpc.json in the Universal-Commerce-Protocol/ucp repository. This OpenRPC schema defines the complete set of EP methods, parameters, and structures, enabling automated client generation and request validation for native host implementations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →