Skip to content

Configuration

AMW is configured with node-config: YAML files located in the config/ directory of the current working directory, plus environment variables for credentials and the most common settings.

Which file is loaded?

NODE_ENV selects the file; AMW sets it to production when it is not defined.

NODE_ENV File Typical use
production (default) config/production.yml npm / Node.js installs; create it from config/sample.yml
docker config/docker.yml set by the Docker image
development config/development.yml npm run dev, the dev container (./start.sh dev)

On top of that file, node-config merges, in this order, local.yml and local-<NODE_ENV>.yml if they exist, then the environment variables mapped by config/custom-environment-variables.yml, and finally the NODE_CONFIG environment variable. Later sources override earlier ones key by key.

Never commit credentials

config/sample.yml, config/docker.yml and config/development.yml are committed and must only contain placeholders or empty values. Put credentials in environment variables (a .env file created from .env.example, which is never committed) or in config/production.yml, which is excluded from the repository, the npm package and the Docker image.

Reference

Amazon

Credentials and defaults for the Amazon Creators API.

Key Sample value Description
Amazon.credentialId <YOUR CREDENTIAL ID> Creators API credential ID.
Amazon.credentialSecret <YOUR CREDENTIAL SECRET> Creators API credential secret.
Amazon.version 3.2 Version of your Creators API credential, as shown in the Creators API dashboard.
Amazon.partnerTag <YOUR PARTNER TAG> Your Associates tracking ID; it is embedded in every product URL returned by Amazon.
Amazon.marketplace www.amazon.fr Marketplace to query, e.g. www.amazon.com, www.amazon.de.
Amazon.condition New Offer condition filter: New or Any.
Amazon.breakerThreshold 5 Consecutive Amazon failures (errors, timeouts, throttling) after which AMW stops calling Amazon for breakerCooldown seconds (circuit breaker). 0 disables it. Defaults to 5 when absent.
Amazon.breakerCooldown 60 Seconds the circuit stays open; then a single trial call decides whether Amazon is back. Defaults to 60 when absent.

Server

Key sample.yml docker.yml Description
Server.port 8080 9080 HTTP port (1-65535). Falls back to 8080 if empty or 0.
Server.debug true false true switches AMW loggers to debug level (full Amazon responses are logged) and exposes error messages in unexpected HTTP 500 responses. Use false in production.
Server.path /amw /item Base path of every endpoint. Must start with /; defaults to /amw if empty. The widget expects /item, see API location.
Server.cors false false true adds Access-Control-Allow-Origin: * to every response. Only needed if pages on other origins call the API directly.
Server.projectDir <PATH> /app/ Required. Absolute path of the directory that contains dist/widgets/widget.js (repository clone, installed npm package, or /app/ in Docker). The path must not contain hidden (dot) directories: the file is then refused and /widget.js answers 500.
Server.httpCache 3600 604800 max-age in seconds of the Cache-Control: public, max-age=โ€ฆ header sent with found products and widget.js (every other response is no-store). For products it is lowered so that a browser or CDN never keeps a product past 24 hours after the Amazon call. Falls back to 300 if empty or 0; must not be negative.
Server.rateLimit 120 120 Maximum /product requests per client IP per one-minute window; beyond it AMW answers HTTP 429. Defaults to 120 when the key is absent. Counters are kept in memory, per AMW process.
Server.clickRateLimit 60 60 Maximum /click beacons (sent by the widget when a reader clicks a card) per client IP per minute. Defaults to 60 when absent.
Server.swagger false false true serves an interactive Swagger UI at <path>/docs/ and the OpenAPI document at <path>/openapi.json. Off by default (and when absent) to keep the public surface minimal.
Server.metrics false false true exposes Prometheus metrics at <path>/metrics. Off by default (and when absent): the endpoint has no authentication, expose it to your monitoring network only.
Server.trustProxy false 1 Express trust proxy setting, which decides how the client IP is derived from X-Forwarded-For: false (use the socket address), a number of proxy hops (e.g. 1 behind a single NGINX), or a list of trusted addresses/subnets such as loopback, 10.0.0.0/8. Avoid true: it trusts any X-Forwarded-For value. Any trusted hop must be the only way to reach AMW, otherwise clients can forge their IP and bypass every rate limit: the Docker default 1 assumes the port is only reachable by the local reverse proxy (published on 127.0.0.1). Defaults to false when absent. Can be set with SERVER_TRUST_PROXY.

Redis

Key sample.yml docker.yml Description
Redis.enabled false false Must be the boolean true to enable the cache; any other value disables it.
Redis.host localhost localhost Redis host.
Redis.port 6379 6379 Redis port.
Redis.username empty empty Redis ACL user name (optional).
Redis.password empty empty Redis password (optional).
Redis.expire 3600 43200 Freshness of cached products, in seconds: within it, AMW answers from the cache without calling Amazon. Must be positive; defaults to 3600 if empty or 0. Values above 86400 are capped at 86400 with a startup warning, see Amazon price freshness.
Redis.staleExpire 86400 43200 Extra seconds a product is kept after Redis.expire, so that it can still be served when Amazon fails or the circuit breaker is open. A product is never served more than 24 hours after the Amazon call, whatever this value. 0 disables it. Defaults to 86400 when absent.
Redis.notFoundExpire 3600 3600 Seconds a product Amazon does not know is remembered, so that a missing ASIN does not cost an Amazon call on every view. Kept in Redis, or in memory (1,000 entries at most) when Redis is disabled. 0 disables it. Defaults to 3600 when absent.

When Redis is enabled, AMW connects at startup and exits if Redis is unreachable. If Redis becomes unavailable later, requests still succeed by calling Amazon directly, and /health reports "redis": "disconnected". The Docker Compose stacks enable Redis with REDIS_ENABLED=true and REDIS_HOST=redis.

Admin

The administration portal is off by default. Its password, signing secret and Claude API key are environment variables only, see Enabling it.

Key sample.yml docker.yml Description
Admin.enabled false false Must be the boolean true to serve the portal at <path>/admin/; the server then refuses to start without AMW_ADMIN_PASSWORD (12 characters at least). Statistics need Redis.
Admin.tokenTtl 3600 3600 Session lifetime, in seconds.
Admin.loginRateLimit 10 10 Failed logins allowed per IP every 15 minutes.
Admin.insights false false Must be the boolean true to enable the AI insights, which send the aggregated statistics to the Claude API. Needs ANTHROPIC_API_KEY.

Environment variables

config/custom-environment-variables.yml maps the following variables onto configuration keys, whatever the NODE_ENV. Unset or empty variables are ignored and the YAML value is kept. Variables marked JSON are parsed as JSON, so write true, false or a number.

Variable Configuration key Format
AMAZON_CREDENTIAL_ID Amazon.credentialId string
AMAZON_CREDENTIAL_SECRET Amazon.credentialSecret string
AMAZON_CREDENTIAL_VERSION Amazon.version string
AMAZON_PARTNER_TAG Amazon.partnerTag string
AMAZON_MARKETPLACE Amazon.marketplace string
AMAZON_BREAKER_THRESHOLD Amazon.breakerThreshold JSON
AMAZON_BREAKER_COOLDOWN Amazon.breakerCooldown JSON
SERVER_PORT Server.port JSON
SERVER_DEBUG Server.debug JSON
SERVER_PATH Server.path string
SERVER_CORS Server.cors JSON
SERVER_PROJECT_DIR Server.projectDir string
SERVER_RATE_LIMIT Server.rateLimit JSON
SERVER_SWAGGER Server.swagger JSON
SERVER_METRICS Server.metrics JSON
SERVER_CLICK_RATE_LIMIT Server.clickRateLimit JSON
SERVER_TRUST_PROXY Server.trustProxy JSON (1, false, or a list such as ["loopback","10.0.0.0/8"])
REDIS_ENABLED Redis.enabled JSON
REDIS_HOST Redis.host string
REDIS_PORT Redis.port JSON
REDIS_USERNAME Redis.username string
REDIS_PASSWORD Redis.password string
REDIS_STALE_EXPIRE Redis.staleExpire JSON
REDIS_NOT_FOUND_EXPIRE Redis.notFoundExpire JSON
AMW_ADMIN_ENABLED Admin.enabled JSON
AMW_ADMIN_TOKEN_TTL Admin.tokenTtl JSON
AMW_ADMIN_LOGIN_RATE_LIMIT Admin.loginRateLimit JSON
AMW_ADMIN_INSIGHTS Admin.insights JSON

Amazon.condition, Server.httpCache and Redis.expire have no variable: set them in a YAML file (for Docker, a mounted local.yml).

.env.example lists the variables: copy it to .env, which is never committed. Both Docker Compose files and docker run --env-file .env read it; for a local Node.js run, export the variables in your shell.

Other variables:

Variable Effect
NODE_ENV Selects config/<NODE_ENV>.yml. Defaults to production; the Docker image sets docker.
NODE_CONFIG JSON document merged on top of everything else, e.g. NODE_CONFIG='{"Server":{"httpCache":86400}}'.
NODE_CONFIG_DIR Directory containing the configuration files (default: ./config).
AMW_ADMIN_PASSWORD Admin portal password (required when Admin.enabled, 12 characters at least).
AMW_ADMIN_SECRET Signing key of the admin tokens; random when unset, which logs admins out on every restart.
ANTHROPIC_API_KEY Claude API key used by the AI insights (Admin.insights).
AMW_DEV_PORT Host port of the development container (default 8080), see Development environment.

Docker defaults

config/docker.yml as shipped in the image (credentials are empty on purpose: provide them with environment variables):

# Configuration baked into the production Docker image (NODE_ENV=docker).
# Credentials are intentionally empty: provide them through the environment
# variables listed in config/custom-environment-variables.yml.

Amazon:
  credentialId: ""
  credentialSecret: ""
  version: "3.2"
  partnerTag: ""
  marketplace: www.amazon.fr
  condition: New
  # Circuit breaker: after breakerThreshold consecutive Amazon failures, stop
  # calling Amazon for breakerCooldown seconds (stale products are served, or
  # 503 with Retry-After). 0 disables the breaker.
  breakerThreshold: 5
  breakerCooldown: 60

Server:
  port: 9080
  debug: false
  path: /item
  cors: false
  projectDir: /app/
  httpCache: 604800
  rateLimit: 120
  swagger: false
  metrics: false
  # Click beacons per minute and per client IP
  clickRateLimit: 60
  # One proxy hop: the documented deployment puts a reverse proxy on the host in
  # front of AMW. The client IP is then read from X-Forwarded-For, which a client
  # reaching the container directly can forge: publish the port on 127.0.0.1 only
  # (as docker/docker-compose.yml does), or set SERVER_TRUST_PROXY=false when AMW
  # is exposed without a proxy.
  trustProxy: 1

# Disabled by default so that a standalone `docker run` (as in the CI smoke
# test) starts without a Redis server: the server refuses to start when Redis
# is enabled but unreachable. docker-compose.yml sets REDIS_ENABLED=true.
Redis:
  enabled: false
  host: localhost
  port: 6379
  password: ""
  username: ""
  # Amazon Associates rules require prices less than 24 h old: larger values
  # are capped at 86400.
  expire: 43200
  # Products are kept staleExpire seconds after they expire, to be served when
  # Amazon is down (0 disables it). Never beyond 24 h after the Amazon call.
  staleExpire: 43200
  # Products Amazon does not know are remembered for notFoundExpire seconds
  # (in memory when Redis is disabled; 0 disables it).
  notFoundExpire: 3600

# Administration portal and usage statistics (statistics require Redis).
# "enabled" can be set with AMW_ADMIN_ENABLED (custom-environment-variables.yml).
# The password is only read from the AMW_ADMIN_PASSWORD environment variable
# (at least 12 characters); the server refuses to start when it is missing.
# AMW_ADMIN_SECRET sets the token signing key (random at startup otherwise,
# which logs admins out on restart). Both are environment-only on purpose.
# Privacy: only aggregated daily counters (90-day retention) and the URL of the
# pages embedding the widget (without query string) are stored; never an
# IP address, a user agent or a cookie.
Admin:
  enabled: false
  tokenTtl: 3600
  loginRateLimit: 10
  # AI insights in the portal: sends the aggregated statistics of the period (counters,
  # product titles, page URLs without query string) to the Claude API, which bills each
  # analysis. Needs ANTHROPIC_API_KEY in the environment.
  insights: false

Development defaults

config/development.yml, loaded by npm run dev and the dev container:

# Configuration for development (NODE_ENV=development: `npm run dev` and
# docker/docker-compose.dev.yml).
# This file is committed, so it must never hold credentials: put them in a
# git-ignored .env file (see .env.example), custom-environment-variables.yml
# maps them onto these keys.

Amazon:
  credentialId: ""
  credentialSecret: ""
  version: "3.2"
  partnerTag: ""
  marketplace: www.amazon.fr
  condition: New
  # Circuit breaker: after breakerThreshold consecutive Amazon failures, stop
  # calling Amazon for breakerCooldown seconds (stale products are served, or
  # 503 with Retry-After). 0 disables the breaker.
  breakerThreshold: 5
  breakerCooldown: 60

Server:
  port: 8080
  debug: true
  path: /amw
  cors: false
  # Must be absolute (Express sendFile). This is the path inside the dev
  # container; set SERVER_PROJECT_DIR when running `npm run dev` on the host.
  projectDir: /app/
  # Short HTTP cache so that widget changes show up on reload
  httpCache: 60
  rateLimit: 120
  metrics: false
  trustProxy: false

# Disabled so that `npm run dev` works on the host without Redis; the dev
# compose file enables it and points it to its own Redis service.
Redis:
  enabled: false
  host: localhost
  port: 6379
  password: ""
  username: ""
  # Amazon Associates rules require prices less than 24 h old: larger values
  # are capped at 86400.
  expire: 3600
  # Products are kept staleExpire seconds after they expire, to be served when
  # Amazon is down (0 disables it). Never beyond 24 h after the Amazon call.
  staleExpire: 86400
  # Products Amazon does not know are remembered for notFoundExpire seconds
  # (in memory when Redis is disabled; 0 disables it).
  notFoundExpire: 3600

Complete sample

config/sample.yml, the starting point for config/production.yml:

Amazon:
  credentialId: <YOUR CREDENTIAL ID>
  credentialSecret: <YOUR CREDENTIAL SECRET>
  version: "3.2"
  partnerTag: <YOUR PARTNER TAG>
  marketplace: www.amazon.fr
  condition: New
  # Circuit breaker: after breakerThreshold consecutive Amazon failures, stop
  # calling Amazon for breakerCooldown seconds (stale products are served, or
  # 503 with Retry-After). 0 disables the breaker.
  breakerThreshold: 5
  breakerCooldown: 60

Server:
  port: 8080
  debug: true
  path: /amw
  cors: false
  projectDir: <PATH WHERE THE PROJECT IS INSTALLED>
  httpCache: 3600
  rateLimit: 120
  swagger: false
  metrics: false
  # Click beacons per minute and per client IP
  clickRateLimit: 60
  trustProxy: false

Redis:
  enabled: false
  host: localhost
  port: 6379
  password:
  username:
  # Amazon Associates rules require prices less than 24 h old: larger values
  # are capped at 86400.
  expire: 3600
  # Products are kept staleExpire seconds after they expire, to be served when
  # Amazon is down (0 disables it). Never beyond 24 h after the Amazon call.
  staleExpire: 86400
  # Products Amazon does not know are remembered for notFoundExpire seconds
  # (in memory when Redis is disabled; 0 disables it).
  notFoundExpire: 3600

# Administration portal and usage statistics (statistics require Redis).
# "enabled" can be set with AMW_ADMIN_ENABLED (custom-environment-variables.yml).
# The password is only read from the AMW_ADMIN_PASSWORD environment variable
# (at least 12 characters); the server refuses to start when it is missing.
# AMW_ADMIN_SECRET sets the token signing key (random at startup otherwise,
# which logs admins out on restart). Both are environment-only on purpose.
# Privacy: only aggregated daily counters (90-day retention) and the URL of the
# pages embedding the widget (without query string) are stored; never an
# IP address, a user agent or a cookie.
Admin:
  enabled: false
  tokenTtl: 3600
  loginRateLimit: 10
  # AI insights in the portal: sends the aggregated statistics of the period (counters,
  # product titles, page URLs without query string) to the Claude API, which bills each
  # analysis. Needs ANTHROPIC_API_KEY in the environment.
  insights: false