Site config
- Written for
- + Written for
- Deprecated
- + Deprecated
- Applies to
- + Applies to
Site config
A site's SiteConfig controls everything about how the banner behaves for that property: theme, copy, categories, blocking mode, geo rules, IAB framework, Google Consent Mode wiring, and more. It's the same object the embed fetches at runtime from the public, unauthenticated GET /config/:cbid — these /v1 routes are the authenticated read/write path for managing it programmatically, e.g. from a CI pipeline or an internal admin tool.
Requires the sites scope: sites:read to read, sites:write to save. See sites for how a cbid is created, and authentication & scopes for scoped keys in general.
GET /v1/sites/:cbid/config
Returns the current config, or a fresh default config if the site has never been configured. This endpoint never 404s for a config that doesn't exist yet — only for an unknown or foreign cbid (the site lookup happens first).
curl https://api.cookiemunch.net/v1/sites/acme-com-9f3k/config \
-H "Authorization: Bearer fck_…" \
-H "User-Agent: Mozilla/5.0"{
"cbid": "acme-com-9f3k",
"ver": 1,
"banner": {
"type": "multilevel",
"layout": "bottom",
"theme": { "background": "#0b0f1a", "text": "#f5f5f5", "highlight": "#5b8def" }
},
"categories": {},
"blocking": { "mode": "auto" },
"i18n": { "defaultCulture": "en", "autoDetect": true },
"framework": "none",
"consentMode": { "enabled": true, "mode": "advanced", "waitForUpdate": 500 },
"defaultMode": "opt-in",
"bots": { "suppress": true },
"consent": { "version": 1 }
}import { createCookieMunch } from '@cookiemunch/sdk';
const fc = createCookieMunch({ apiKey: process.env.FC_KEY, baseUrl: 'https://api.cookiemunch.net' });
const config = await fc.sites.getConfig('acme-com-9f3k');PUT /v1/sites/:cbid/config
Saves the config. The request body is a SiteConfig object (v1 inline shape shown above, or a v2 { v: 2, flow, categories, ... } document from Banner Studio).
Important — this is not a deep merge against your saved config. The server normalizes whatever you send by merging it over a fresh default config (
defaultConfig(cbid)), not over what's currently stored, then overwrites the record wholesale. Concretely:banner,categories,blocking,i18n,consentMode,consent,bots,tcf,gpp,usPrivacy,adPersonalization,controller, andwithdrawalare each shallow-merged onto their default value (so a partial{ "banner": { "type": "inline" } }keeps the default theme/layout, not whatever theme you'd previously saved);framework,defaultMode,geoRules,consentSync, andjurisdictionare replaced outright when present in the patch, and otherwise fall back to the default. Any top-level field you omit reverts to its default, it does not keep its previously-saved value. To change one field safely,GETthe current config first, edit the object client-side, andPUTthe whole thing back — that's what the dashboard and the SDK examples below do implicitly by round-tripping the full object.
curl -X PUT https://api.cookiemunch.net/v1/sites/acme-com-9f3k/config \
-H "Authorization: Bearer fck_…" \
-H "User-Agent: Mozilla/5.0" \
-H "Content-Type: application/json" \
-d '{
"blocking": { "mode": "auto", "ignoreSelectors": [".fc-first-party"] },
"defaultMode": "opt-in",
"framework": "iab"
}'{
"cbid": "acme-com-9f3k",
"ver": 1,
"banner": { "type": "multilevel", "layout": "bottom", "theme": { "background": "#ffffff", "text": "#111111", "highlight": "#2563eb" } },
"categories": {},
"blocking": { "mode": "auto", "ignoreSelectors": [".fc-first-party"] },
"i18n": { "defaultCulture": "en", "autoDetect": true },
"framework": "iab",
"consentMode": { "enabled": true, "mode": "advanced", "waitForUpdate": 500 },
"defaultMode": "opt-in",
"bots": { "suppress": true },
"consent": { "version": 1 }
}Note banner.theme came back as the default palette, not any previously-saved custom theme, because this request's banner key was omitted — see the merge caveat above.
// Safe partial update: read-modify-write.
const current = await fc.sites.getConfig('acme-com-9f3k');
const updated = await fc.sites.putConfig('acme-com-9f3k', {
...current,
framework: 'iab',
blocking: { ...current.blocking, ignoreSelectors: ['.fc-first-party'] },
});Key fields
Field | Type | Description |
|---|---|---|
| object |
|
| object | Per-category label/description overrides for the four standard categories (necessary/preferences/statistics/marketing). |
| object |
|
| object |
|
|
|
|
| object | Google Consent Mode v2 wiring: |
| array | Ordered |
|
| Banner mode when no |
| object | A/B test config: |
| object |
|
| object | IAB TCF publisher settings, Global Privacy Platform, and legacy US Privacy string config, respectively. |
| object / object / string | Data-controller identity and consent-withdrawal info surfaced on signed receipts. |
| object |
|
Errors
404 if the cbid is unknown or belongs to another org. 400 with structured issues when a v2 flow config fails server-side validation or lint:
{
"error": "invalid_config",
"issues": [
{ "code": "unknown_start_view", "message": "flow.start references a view id that doesn't exist", "path": "flow.start" }
]
}Note — plan gating. Plan limits are enforced here too, not just in the dashboard UI. If your org is on a plan without the relevant feature, the server silently resets the offending field before saving rather than erroring:
framework: "iab"reverts to"none"(and anytcfblock,autoFrameworkByRegion, and v2tcfPanel/tcfVendorCountflow elements are stripped) withouttcfaccess;banner.content.poweredByis forced back totruewithout white-labeling; andexperiment.enabledis forced tofalsewithout A/B testing. A scoped automation key can never bypass plan limits this way, but the response also won't flag that it happened — diff the response body against what you sent if a premium field doesn't seem to take effect.
POST /v1/sites/:cbid/elements/ad-personalization
A narrower, idempotent helper for one specific toggle: enables (or disables) the personalized-vs-basic ad split on whichever banner form the site uses (inline v1 or a v2 flow), injecting the in-banner toggle element into a v2 flow automatically when needed.
Field | Type | Required | Description |
|---|---|---|---|
| boolean | no | Defaults to |
| boolean | no | Default state of the toggle for new visitors. |
| string | no | Custom label for the injected element. |
curl -X POST https://api.cookiemunch.net/v1/sites/acme-com-9f3k/elements/ad-personalization \
-H "Authorization: Bearer fck_…" \
-H "User-Agent: Mozilla/5.0" \
-H "Content-Type: application/json" \
-d '{ "enabled": true }'{ "ok": true, "form": "flow", "enabled": true, "injectedElement": true }form is "flow" for a v2 config or "inline" for v1 (inline banners render the toggle from the config flag directly, so no element injection is needed — note may explain why injection was skipped on a flow site, e.g. no matching view).
Related: programmatic flow editing
Sites on a v2 (Banner Studio) config also expose GET/PUT /v1/sites/:cbid/flow (read the flow plus lint issues, or wholesale-replace it) and POST /v1/sites/:cbid/flow/ops (apply structured edit operations) as an alternative to sending a raw flow object through this page's PUT .../config. Both paths persist through the same plan-gating and validation as PUT .../config; 501 if flow ops aren't configured on this deployment. See the @cookiemunch/sdk's fc.sites.getFlow() / fc.sites.editFlow() / fc.sites.setFlow() for the typed client methods.
Next: consent log, stats & export to read the decisions this config produces, or cookies, scan & verify to populate the cookie declaration a cookieTable element renders.