Get your first signed consent receipt
Give visitors on your site a way to choose which emails they receive. You will need access to its DNS, an HTTPS backend and a test email address you control. A workspace owner or admin with MFA registers the site. A developer keeps the signing key on the company's backend.
Add your site and prove you own it
- Add your site.
Open Company โ Sites & apps, choose Add a site or app and enter the product name and domain. Save site draft lets you resume in the same browser and account.
- Choose how to verify visitors.
For sign-in handled by your site, select the identity provider and enter your web client ID. For a site using verified email through EVP, choose Verified email (EVP). Enter the exact HTTPS page where visitors should return, such as
https://your-site.example/xcim/return. Use the same host as the site for self-service registration. Choose Add site to workspace. - Verify the site domain.
At your DNS provider, add the TXT name and value shown in the console. Select Check DNS. If you leave, reopen the site in Setup. If your DNS proof is older than 30 days, use Renew DNS verification to issue a fresh challenge before registering.
Register the application with its public key
Use your existing backend Ed25519 key, or create a dedicated key for this test. For a local test, run the following with Node.js 22 or later from a private server directory. The command creates a new file and prints the public value for the console. For production keep your private key in your key manager.
node -e "const {generateKeyPairSync}=require('node:crypto');const {privateKey,publicKey}=generateKeyPairSync('ed25519');require('node:fs').writeFileSync('xcim-test.pem',privateKey.export({type:'pkcs8',format:'pem'}),{flag:'wx',mode:0o600});console.log(publicKey.export({format:'jwk'}).x)"In Setup, paste the 43-character public value in Application public key and choose Register application. Open Application registration details for the application ID and current key ID. If the connection drops, retry with the same public key. Sites that already have an application can continue in its existing Setup.
In the shell on your test backend set these values. Pick a unique manifest ID for your first set of consent choices. The examples below use shell export syntax.
export XCIM_APP_ID='urn:xcim:app:your-registered-application'
export XCIM_APP_KEY_ID='your-registered-key-id'
export XCIM_TEST_KEY_FILE='./xcim-test.pem'
export XCIM_MANIFEST_ID='urn:xcim:manifest:your-company-news-v1'Publish the visitor choices and authorize the return
- Publish your first set of choices.
Download the choices template as
choices.json. Enter your application display name, email purposes, frequency, actual sender domain and HTTPS privacy policy. On the server, sign your choices.node first-receipt.cjs sign-manifest ./choices.jsonIn Setup โ Manage signed manifests, paste the output, verify the signature, review and confirm publication. This initial version can serve visitors immediately when effective. To customize its appearance, open Consent screen, adjust the logo and colors, save the draft and publish it. Appearance-only publication can reuse the signed choices. See publishing and later text changes.
- Register the return address.
Under Register the return URL, review and confirm the exact HTTPS destination on your site. If the URL already shows as configured, continue.
- Authorize the domain's role.
In Setup โ Authorize return domain (also available under domain settings), enter the host of the return URL. Select Delegated consent presentation, review the scope and issue its DNS challenge. If you will also let an email provider validate lists, authorize Visible From address for the actual sender domain. If both roles use this same host you can select both in one request.
Publish the TXT record shown for the selected roles. Download domain-proof.json from this step and run:
node first-receipt.cjs sign-domain ./domain-proof.jsonPaste the signed output in the domain settings. Review it and choose Check DNS and publish authority. The initial site TXT proves control of the host. This second proof grants specific roles to this application until the expiry you chose.
- Check receipt setup.
Emabled automatically prepares the receipt identity key for newly registered applications. Choose Check receipt setup until this step shows as configured.
Make one choice and verify its receipt
Using EVP? Follow the EVP session and token submission example with a supported verifier and delivery mode. Using site sign-in? Follow the example below and the site sign-in guide to bind the provider's ID token to a fresh consent session.
Copy the site ID from Developer guide and pin the receipt signing key's kid and public x from Emabled's issuer keys. Keep these separate from your application's signing key.
export XCIM_SOURCE_ID='src_your_site'
export XCIM_RETURN_URI='https://your-site.example/xcim/return'
export XCIM_ISSUER_KEY_ID='trusted-receipt-signing-key-id'
export XCIM_ISSUER_PUBLIC_KEY='trusted-receipt-signing-public-x'
node first-receipt.cjs start ./my-first-test.jsonStart your site's sign-in with the nonce printed by the command. Have your backend exchange the provider code and save this session's signed ID token to a private test file. Then run:
export XCIM_TEST_ID_TOKEN_FILE='./test-id-token.txt'
node first-receipt.cjs submit-identity ./my-first-test.jsonOpen the printed hosted URL in your browser. Make a choice, submit it and confirm the visitor returns to the registered page. On the same backend run:
node first-receipt.cjs check ./my-first-test.jsonA successful check verifies the receipt's signature, application, resolved manifest and session nonce. If issuance is still pending, repeat check. In Setup, Check for a receipt reads the actual application's receipt count. A decline can also produce a receipt.
Already using the Google hosted code relay?
Set XCIM_EXCHANGE_ID to your approved endpoint and leave XCIM_SOURCE_ID unset. If the relay uses a different reviewed application key, set XCIM_BOUND_APP_KEY_ID to its key ID. The start command returns the hosted URL directly. Complete sign-in there and run check against the same file.
Connect your site's button
Have the button call an authenticated route on your backend. Start one XCIM session per visitor and bind the session ID, nonce, resolved manifest and idempotency key to that visitor's server-side session. After verifying their identity, redirect to the hosted consent page. On return, verify that session's signed receipt. The sample's private file holds one test. Reuse it for retries and use a new one for each visitor.
Finally, withdraw one of the purposes your test visitor accepted. Check that the current permission reflects the withdrawal. The signed receipt records the original choice.