Consent Docs

Configuration

Every environment variable a self-hosted deployment reads, grouped by area, with its default and what it does.

Reference12 min readFor anyone looking something up

The API is configured only through environment variables, all listed here.

The API checks them at start-up. An error stops it with a Config error: line in the log. A warning is logged as Config warning:. The product sends no email or SMS, so there are no mail settings.

Values that must never change#

Four values are part of the stored data. A change raises no error at start. It breaks what was recorded before.

Variable What breaks if it changes
ENCRYPTION_KEY Every encrypted field becomes unreadable: readable identifiers, rights request contacts, webhook signing secrets, identity secrets, fingerprint keys and translation keys. Every secret key (sk_…) is refused. Open confirmation, unsubscribe and consent portal links stop working. Values derived from it change too
SUBJECT_HASH_PEPPER No existing record or rights request can be found by identifier. Returning visitors are treated as new
EVIDENCE_CHAIN_KEYS Every event sealed with a removed key fails verification. Adding keys is safe
RECEIPT_SIGNING_PRIVATE_KEY Receipts and anchors signed with the old key no longer pass the console and API checks

An empty value is also a value

While SUBJECT_HASH_PEPPER, EVIDENCE_CHAIN_KEYS or RECEIPT_SIGNING_PRIVATE_KEY is empty, the API takes it from another secret. A different value later is a change. Set all of them before the first consent is recorded. To give a running deployment dedicated values, see Rotate secrets.

Back these values up with the same care as the database.

Server#

Variable Required or default What it does
NODE_ENV Unset. The supplied image sets production production turns on the production checks. The API refuses to start without ENCRYPTION_KEY or PUBLIC_API_URL. The console API refuses localhost origins, demo data and private scan targets
PORT 3003 Port the API listens on. The image's health check expects 3003
LOG_LEVEL log error, warn, log or debug

The API also reads a .env file from its working directory, if one exists.

Database#

Variable Required or default What it does
DB_HOST localhost PostgreSQL host
DB_PORT 5432 PostgreSQL port
DB_USERNAME postgres User. An empty string is an error
DB_PASSWORD postgres. Required by the compose file Password. An empty string is an error
DB_DATABASE piedap_consent Database name. An empty string is an error
DB_MAX_CONNECTIONS 20 Pool size of each API replica. Size the database for replicas times this number
DB_LOGGING false true logs every SQL statement. Statements can hold hashes and consent data, so keep it off in production
DB_SYNCHRONIZE false Lets the ORM alter the schema to match the code. Leave it unset. Migrations own the schema

The API applies pending migrations when it starts. It tries the database connection ten times, three seconds apart, then exits. The database user must be allowed to create the uuid-ossp extension on first start.

Overview dashboards#

The charts of the console's Overview query the database directly. These two settings keep them from crowding out consent writes.

Variable Required or default What it does
DASHBOARD_STATEMENT_TIMEOUT_MS 5000 Time limit, in milliseconds, for a chart query that reads single records or events. Kept between 1000 and 15000. Other chart queries stop after 3000
DASHBOARD_MAX_STATEMENTS 30% of DB_MAX_CONNECTIONS, at most 6, at least 2 Chart queries one API replica runs at once, kept between 2 and half of DB_MAX_CONNECTIONS. Single-record and event queries may use all but two, and at least one

Defaults and limits lists the other limits on chart queries.

Redis#

Variable Required or default What it does
REDIS_HOST localhost. Required for the console The Redis that IAM writes sessions to. It also shares rate-limit counters between replicas
REDIS_PORT 6379 Redis port
REDIS_PASSWORD None Redis password

Without Redis the SDK surface still works and each process counts rate limits by itself. Nobody can sign in to the console.

Secrets and keys#

Variable Required or default What it does
ENCRYPTION_KEY Required Encrypts stored secrets with AES-256-GCM, and salts secret-key hashes and link tokens. It is the fallback source for the keys below. Any long random string
SUBJECT_HASH_PEPPER ENCRYPTION_KEY. Recommended Key of the HMAC-SHA256 hash of every identifier, and salt of the IP address hash
EVIDENCE_CHAIN_KEYS Derived from ENCRYPTION_KEY. Recommended Keys that seal consent events, as id:secret,id:secret. An id is 1 to 40 letters, digits, _ or -. A secret is at least 32 characters with no comma
EVIDENCE_CHAIN_ACTIVE_KEY The last key listed Id of the key that seals new events. It must be one of the listed ids
RECEIPT_SIGNING_PRIVATE_KEY Derived from RECEIPT_SIGNING_KEY, else ENCRYPTION_KEY. Recommended Ed25519 key that signs receipts and daily anchors. A PKCS#8 PEM, where \n may stand for line breaks, or a base64 32-byte seed
RECEIPT_SIGNING_KEY_ID ed plus the first ten hex characters of the SHA-256 hash of the public key Published as the key's kid at /sdk/v1/keys and written on receipts and anchors
RECEIPT_SIGNING_KEY ENCRYPTION_KEY. Recommended Checks receipts issued in the earlier HMAC format. It is the source of the derived signing key and chain key when those are not set
EVIDENCE_SIGNING_KEY None An older source of the chain key, used when EVIDENCE_CHAIN_KEYS is empty. Leave it unset on a new deployment

In production the API warns when SUBJECT_HASH_PEPPER or RECEIPT_SIGNING_KEY is not set. In every mode it refuses to start when the chain keys or the signing key are malformed, or when no secret exists to derive them from.

IAM#

The console has no accounts of its own. These values must match the PIEDAP IAM deployment that signs people in.

Variable Required or default What it does
LOGIN_COOKIE None. Required for the console Name of the session cookie IAM sets
LOGIN_SECRET None. Required for the console Secret that verifies the signature of the session cookie
COOKIE_DOMAIN None. Required for the console Domain of the IAM cookies. The API clears them on sign-out or a failed check; a wrong value leaves a stale cookie
VERIFY_LOGIN_COOKIE None Name of another IAM cookie to clear on sign-out
REFRESH_COOKIE None Name of the IAM refresh cookie to clear on sign-out
BASE_IAM_URL None. Required for API tokens Address of the IAM service. The API calls it to check a bearer token sent to the console API
SERVER_SIDE_API_KEY None. Required for API tokens This service's own key, sent to IAM with that check
IAM_LOGIN_URL None. Recommended Where the console sends someone who is not signed in

Public URLs and proxies#

Variable Required or default What it does
PUBLIC_API_URL http://localhost:3003. Required in production The public address of the deployment, with no trailing slash. Built into install snippets, confirmation links, hosted page links, and the issuer and key address on receipts
RUNTIME_CDN_URL PUBLIC_API_URL Base address of the runtime files in install snippets, when you serve them from a CDN
UI_URL None An origin allowed to call the console API with the session cookie
ADMIN_UI_URL None A second such origin
TRUST_PROXY loopback, linklocal, uniquelocal Which proxies may set X-Forwarded-For: a hop count such as 2, true, false, or a list of addresses and ranges
  • The console API always accepts https origins one level under piedap.com, piedap.in and piedap.io, such as https://app.piedap.io.
  • It accepts http://localhost and http://127.0.0.1 with a port when NODE_ENV is not production.
  • The SDK surface accepts any origin and relies on each key's allowed origins.
  • If a CDN sets a country header such as CF-IPCountry or CloudFront-Viewer-Country, the API uses it. Otherwise it looks the address up in its own database.

Do not set TRUST_PROXY to true on a public port

With true, any client can choose its own address through X-Forwarded-For. That address picks its rate-limit bucket and is written to the audit log.

Rate limits#

Variable Required or default What it does
RATE_LIMIT_MAX 300 Requests per window from one address to the console API
RATE_LIMIT_SDK_MAX 3000 Requests per window from one address to the SDK surface
RATE_LIMIT_WINDOW_MS 60000 Length of that window in milliseconds
SDK_WRITES_PER_ADDRESS_PER_MINUTE 60 Writes per minute from one address with one publishable key
SDK_CRITICAL_CALLS_PER_MINUTE 60 Calls on a person as a whole (find, export, withdraw, erase, link), notice campaign links and processor tasks, per minute with one secret key
SDK_CHECK_MAX_PER_MINUTE 6000 The most identifiers a minute any key may be allowed to check with consent:check. Lowering it also caps keys set higher

Each key also has its own limit per minute, stored with the key: 600 for a test key and 6,000 once it is live. /health and /metrics are not rate limited. What a caller sees is in Rate limits.

Evidence and retention#

Variable Required or default What it does
ENFORCE_EVIDENCE_RETENTION false true lets the daily retention job delete records whose consent ended longer ago than the project's Keep evidence for period. This cannot be undone. false deletes nothing
STORE_SUBJECT_REFERENCE false Fallback when a project's settings cannot be read: keep an encrypted readable copy of the identifier
PROJECT_DELETION_DAYS 30 Days from scheduling a project's closure to deleting its data, 1 to 365. See Close a project

The job is described in Scheduled jobs.

Variable Required or default What it does
CONSENT_IMPORT_MAX_ROWS 100000 Rows in one file for Import CSV
CONSENT_IMPORT_DAILY_ROWS 100000 Records console imports may write in one project in one UTC day

Audit log#

Variable Required or default What it does
AUDIT_LOG_STDOUT true false stops the one-line JSON copy of each audit entry on standard output
AUDIT_FEED_LAG_SECONDS 60 Entries younger than this are held back from GET /sdk/v1/audit-log. From 5 to 3600
AUDIT_FEED_CALLS_PER_MINUTE 60 Feed calls per minute with one key, on top of the key's own budget

Webhooks and outbound calls#

Variable Required or default What it does
PRIVATE_NETWORK_ALLOWLIST Empty: no private network is reachable Private networks that webhooks may reach when the endpoint's Private network switch is on, and that the translation service may reach. Comma-separated CIDR ranges, addresses and host names
ALLOW_PRIVATE_WEBHOOK_URLS Not read Replaced by PRIVATE_NETWORK_ALLOWLIST. With true, the API refuses to start in production and warns elsewhere
Shell
PRIVATE_NETWORK_ALLOWLIST=10.20.0.0/16,api-gw.bank.internal,*.crm.bank.internal
  • A bare address means that one address. *.crm.bank.internal matches its subdomains, not the name itself.
  • A range wider than /8 is refused, and so is an entry that is none of these. In production that stops start-up; elsewhere it is a warning.
  • 169.254.0.0/16, where cloud metadata services answer, is never reachable, even when listed.
  • In production, a loopback entry or localhost starts with a warning: a webhook could reach services on the API host itself.
  • For a receiver on your own machine in development: 127.0.0.1/32,::1/128,localhost.

Translation#

Variable Required or default What it does
SARVAM_API_KEY None The deployment's own Sarvam key for machine translation of notice wording. Without it, each project adds its own key or chooses another service in Settings

Keys that projects add for a translation service are stored in the database, encrypted with ENCRYPTION_KEY.

Platform key#

Variable Required or default What it does
PLATFORM_API_KEYS None One key per operator, as comma-separated name:sha256 entries, where sha256 hashes that person's key. Their calls record their name. See Approve live keys
PLATFORM_API_KEY None One key the operator's team shares, sent as X-Piedap-Platform-Key. With neither set, the endpoints that approve live keys and set DPDP dates answer 503

Hosting location#

Variable Required or default What it does
DEPLOYMENT_REGION None Where the data is kept, in words, such as India (Mumbai)
DEPLOYMENT_COUNTRY None That country's ISO 3166-1 alpha-2 code, such as IN. Another value stops start-up in production. Unset, production logs a warning
PRODUCT_SCOPE india india offers only the DPDP Act and hides unused IAB and opt-out settings. global offers every law
DEPLOYMENT_PROVIDER None The hosting provider

Every project sees them in Settings and in the DPDP Act check.

Monitoring#

Variable Required or default What it does
METRICS_TOKEN None Bearer token for /metrics. While unset, /metrics answers only clients on loopback or a private network, and 404 to everyone else

Runtime features#

Variable Required or default What it does
DISCOVERY_SAMPLE_RATE 0.05 Share of page views on which the browser runtime reports cookie and storage names
TCF_GVL_URL https://vendor-list.consensu.org/v3/vendor-list.json Where the IAB Global Vendor List is downloaded from. Point it at a mirror if the API has no outbound access
GVL_CACHE_DIR piedap-consent-gvl in the system temp directory Where the vendor list is cached
SCANNER_CHROMIUM_PATH The browser Playwright finds. The supplied image sets /usr/bin/chromium-browser Chromium used for site scans

Development only#

Never set these on a deployment that holds real consent.

Variable Default What it does
AUTH_BYPASS false Skips sign-in and Redis and uses a built-in session. The API refuses to start with it unless NODE_ENV is development or test
SEED_ON_BOOT false Adds starter purposes and a draft form to one project at start
SEED_ORGANIZATION_ID, SEED_ACCOUNT_ID, SEED_PROJECT_ID Fixed development ids The project SEED_ON_BOOT fills
ALLOW_DEMO_DATA false Allows the demo data generator when NODE_ENV is production
ALLOW_PRIVATE_SCAN_TARGETS false Lets scans target private addresses. Ignored when NODE_ENV is production

Build settings#

The API does not read these. They are used when you build the images.

Setting Where Default What it does
INSTALL_SCANNER Build argument of the API image true false leaves Chromium out for a smaller image. Scans then fail
VITE_BASE_PATH Build argument of the console image / Path prefix the console is served under, such as /consent/
VITE_DOCS_URL Build argument of the console image Empty Adds a Documentation link to the Install page. Empty hides it
VITE_PIEDAP_CONSENT_API_URL Console build The console's own origin Address of the API when the console is loaded from another origin
VITE_PIEDAP_CONSENT_HOME_PAGE_URL Module Federation build of the console http://localhost:5176 Where remoteEntry.js is served from when the console loads inside the PIEDAP shell

The console's nginx reaches the API as consent-api:3003 through Docker's DNS. Elsewhere, change web/nginx.conf.

Compose file#

docker-compose.yml passes only the variables it lists to the API container. It also sets DB_HOST, DB_PORT, REDIS_HOST and REDIS_PORT to its own containers, whatever .env says.

Setting Default What it does
CONSENT_DB_HOST_PORT 5436 PostgreSQL's host port, on loopback
DOCS_SITE_URL None Address of the documentation
DOCS_HOST_PORT 8081 Its host port
LAN_IP None compose.lan.yml only: this machine's local network address, used as the demo's public address

Variables it does not pass include TRUST_PROXY, ENFORCE_EVIDENCE_RETENTION, SARVAM_API_KEY, LOG_LEVEL and the rate limits. Set those, or your own database and Redis hosts, in an override file. Compose merges it automatically.

docker-compose.override.ymlYAML
services:
  consent-api:
    environment:
      REDIS_HOST: redis.example.in
      SARVAM_API_KEY: ${SARVAM_API_KEY:-}
      LOG_LEVEL: warn
Service Published on Note
Console 0.0.0.0:8080 Put your reverse proxy in front. To bind it to loopback, set ports: !override ['127.0.0.1:8080:80'] in the override file (Compose 2.24.4 or later). A plain ports entry is added to this one
API 127.0.0.1:3003 Loopback only. Use it for /metrics
PostgreSQL 127.0.0.1:5436 Loopback only
Redis 127.0.0.1:6379 Loopback only

Data is kept in two named volumes, consent-pgdata and consent-redisdata. Docker lists them with the project name in front, as piedap-consent_consent-pgdata.

compose.lan.yml is for demos on a trusted network. It turns sign-in off, so never use it for a real deployment.

↑↓ to move, Enter to open