# Configuration

SleekTrack works without any configuration. The collection settings decide
what the collector records and who it ignores. Open **Settings** in Track's
navigation: its **Collection** section holds them, beside
[Access](/docs/track/access.md). **Discard** drops the changes you have not
saved; **Save** saves them. The older address `#/track/settings/collection`
still opens the section.

## How settings resolve

Every setting keeps the plugin default until you turn on **Override plugin
default** beside it and choose a value. In the network admin, the same screen
sets network values, and **Enforce across network** applies a value to every
enabled site. Click **Save** to store the changes.

A setting's value comes from the first of these that sets it:

1. A constant defined in `wp-config.php`
2. A value the network enforces
3. The site's own override
4. The SleekTrack default

Each setting shows where its value comes from: **WP Config**, **Network**,
**This site** or **Default**. A value managed in `wp-config.php` or by the
network administrator is shown but cannot be edited on the site.

The site's values are stored in the `sleektrack_settings` option and the
network's in a network option; read and change them through the
`Settings_read` and `Settings_save` operations, or `Network_settings` and
`Network_settingsPost` for the network, rather than writing the options.
[Settings](/docs/track/reference/settings.md) and
[REST operations](/docs/track/reference/rest.md) list them.

## Constants

Each setting has a constant that fixes its value for the whole install:

| Setting                        | Constant                       | Default |
| ------------------------------ | ------------------------------ | ------- |
| Trusted proxy headers          | `SLEEKTRACK_TRUSTED_PROXY`     | off     |
| Data retention (days)          | `SLEEKTRACK_RETENTION_DAYS`    | 365     |
| Requests per minute            | `SLEEKTRACK_RATE_LIMIT`        | 100     |
| Custom country header          | `SLEEKTRACK_COUNTRY_HEADER`    | none    |
| Persistent database connection | `SLEEKTRACK_PERSISTENT_DB`     | off     |
| Page titles                    | `SLEEKTRACK_COLLECT_TITLES`    | on      |
| Scroll depth                   | `SLEEKTRACK_COLLECT_SCROLL`    | on      |
| City-level geolocation         | `SLEEKTRACK_CITY_DATABASE`     | off     |
| Excluded roles                 | `SLEEKTRACK_EXCLUDED_ROLES`    | none    |
| Excluded IP addresses          | `SLEEKTRACK_EXCLUDED_IPS`      | none    |
| Blocked referrers              | `SLEEKTRACK_BLOCKED_REFERRERS` | none    |

Define them in `wp-config.php` with a literal value:

```php
define('SLEEKTRACK_RETENTION_DAYS', 90);
define('SLEEKTRACK_EXCLUDED_IPS', '203.0.113.7, 10.0.0.0/8');
```

The collector answers tracking requests before regular plugins and the theme
load, and reads these constants from `wp-config.php` itself. A constant
defined in a plugin or in a theme's `functions.php` does not reach it, even
though the settings screen may show it as set.

## Behind Cloudflare or a reverse proxy

By default SleekTrack identifies visitors by the connecting IP address
(`REMOTE_ADDR`). Behind Cloudflare, a load balancer or any reverse proxy, that
is the proxy's address, so every visitor would look the same.

The best fix is to configure the web server, for example Apache's
`mod_remoteip` or Nginx's `real_ip` module, so the real visitor address lands
in `REMOTE_ADDR`. If you cannot, turn on **Trusted proxy headers**: SleekTrack
then reads the visitor's address from `CF-Connecting-IP`, `X-Real-IP` or the
first address of `X-Forwarded-For`, in that order.

To trust only the header your proxy sets, name it in `wp-config.php`:

```php
define('SLEEKTRACK_TRUSTED_PROXY_HEADER', 'CF-Connecting-IP');
```

SleekTrack then reads only that header. Named `X-Forwarded-For`, it reads the
address your proxy added last rather than the first one, which a visitor could
have sent.

Turn it on only when a trusted proxy really sits in front of the site.
Forwarding headers are easy to forge, so trusting them on a directly exposed
site would let anyone fake visitor counts.

## Data retention

SleekTrack keeps 365 days of raw events by default and deletes older ones in
small batches during its daily background task. Set **Data retention (days)**
between 0 and 36500; 0 keeps events forever. Daily totals are kept beside the
events, so the charts and totals of pruned days remain, without their
breakdowns. Pruning waits while SleekTrack is still building daily totals for
older history.

## Rate limiting

The collector accepts up to **Requests per minute** requests from one IP
address, 100 by default. The count is kept per WordPress site (on a network,
per enabled site), not per tracked domain, so requests from one address to
every domain the install tracks share one limit. It uses APCu when the server
has it and otherwise a small table of its own, which an hourly task clears of
past minutes.

## Country headers

SleekTrack reads the visitor's country from headers that Cloudflare,
CloudFront, Vercel, an `X-Country-Code` header or a GeoIP-enabled web server
supply. Cloudflare, CloudFront and Vercel can also supply the region and city.
Set **Custom country header** to read a two-letter country code from another
trusted header first, for example `X-Edge-Country`.

Trust only a header that your proxy or web server overwrites. A header a
visitor sends directly can be forged.

## City-level geolocation

Turn on **City-level geolocation** to resolve regions and cities on your own
server when no edge header supplies them. The daily background task then
downloads the free DB-IP City Lite database and refreshes it once a month; the
collector looks each visitor's IP address up in that local file. No visitor
data is sent to DB-IP or anyone else. [Privacy](/docs/track/privacy.md#location)
covers the file and its licence.

Turning the setting off stops the lookups at once, and the daily task deletes
the file when no site of the network still uses it.

## Page titles and scroll depth

**Page titles** stores the title sent with each pageview, which the **Titles**
tab of the Top pages card reports. **Scroll depth** stores how far each page
was scrolled, which its **Scroll depth** tab reports. Both are on by default; while
one is off, the collector stores nothing for it.

## Excluded visitors

- **Excluded roles**: logged-in users with these roles are not tracked on the
  install that tracks itself, and their orders are not recorded as revenue.
  Turn on each of the site's roles to exclude, or **Every logged-in user**.
  The setting is stored as role slugs, one per line, with `all` for every
  logged-in user, and `SLEEKTRACK_EXCLUDED_ROLES` takes the same text, such
  as `'administrator, editor'`; a stored role the site no longer has still
  shows, so it can be turned off
- **Excluded IP addresses**: the collector ignores visits from these addresses
  or CIDR ranges, such as `10.0.0.0/8`, on every tracked site
- **Blocked referrers**: the collector ignores traffic referred from these
  domains and their subdomains, in addition to the built-in spam list

The address and referrer lists take one entry per line. A list saved with
commas, or set in `wp-config.php` with them, still works, and the screen
shows it one entry per line.

## Persistent database connection

For very high traffic, **Persistent database connection** lets the collector
reuse its MySQL connections, a small speed gain at the cost of more open
connections. Leave it off unless you have measured a need and your database
is configured for the extra connections.

## AI provider keys

The Track assistant uses the AI provider keys of the global Settings panel,
opened from the settings button beside the light and dark mode control. Its
**AI** section takes one key each for OpenAI, Anthropic, Google and
OpenRouter; every product's assistant and AI feature shares them, and a key is
stored encrypted and never shown again. The standalone plugin shows the same
section in its Settings. Without a key, the assistant's history stays readable
but it cannot answer.
