diff --git a/snippets/nuxt/server/utils/ProxiesConfig.js b/snippets/nuxt/server/utils/ProxiesConfig.js deleted file mode 100644 index f8e0b735..00000000 --- a/snippets/nuxt/server/utils/ProxiesConfig.js +++ /dev/null @@ -1,9 +0,0 @@ -import { arcjet as arcjetNuxt } from "#arcjet"; - -export const arcjet = arcjetNuxt({ - rules: [], - proxies: [ - "100.100.100.100", // A single IP - "100.100.100.0/24", // A CIDR for the range - ], -}); diff --git a/snippets/nuxt/server/utils/ProxiesConfig.ts b/snippets/nuxt/server/utils/ProxiesConfig.ts index 1836bf7b..3add67cd 100644 --- a/snippets/nuxt/server/utils/ProxiesConfig.ts +++ b/snippets/nuxt/server/utils/ProxiesConfig.ts @@ -2,9 +2,9 @@ import { arcjet as arcjetNuxt } from "#arcjet"; export const arcjet = arcjetNuxt({ - rules: [], proxies: [ - "100.100.100.100", // A single IP - "100.100.100.0/24", // A CIDR for the range + "76.76.21.21", // An IP address. + "103.21.244.0/22", // A CIDR range of IP addresses. ], + rules: [], }); diff --git a/snippets/nuxt/server/utils/TrustedIp.ts b/snippets/nuxt/server/utils/TrustedIp.ts new file mode 100644 index 00000000..82cacc8a --- /dev/null +++ b/snippets/nuxt/server/utils/TrustedIp.ts @@ -0,0 +1,9 @@ +// @ts-expect-error +import { arcjet as arcjetNuxt, slidingWindow } from "#arcjet"; + +export const arcjet = arcjetNuxt({ + // To illustrate, allow 3 requests per minute per IP address. + rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })], + // Assumes requests will have an `x-my-ip` header that you trust: + trustedIpHeader: "x-my-ip", +}); diff --git a/src/content/docs/concepts/client-ip.mdx b/src/content/docs/concepts/client-ip.mdx new file mode 100644 index 00000000..722f9c46 --- /dev/null +++ b/src/content/docs/concepts/client-ip.mdx @@ -0,0 +1,393 @@ +--- +description: "How the client IP is detected in Arcjet and how to change that." +frameworks: + - astro + - bun-hono + - bun + - deno + - fastify + - nest-js + - next-js + - node-js-express + - node-js-hono + - node-js + - nuxt + - react-router + - remix + - sveltekit +next: false +prev: false +title: "Client IP" +ajToc: + - anchor: "overview" + text: "Overview" + - anchor: "framework" + text: "Framework" + - anchor: "platform" + text: "Platform" + - anchor: "proxies" + children: + - anchor: "ip-ranges" + text: "IP ranges" + text: "Proxies" + - anchor: "overwriting-client-ips" + children: + - anchor: "development" + text: "Development" + - anchor: "production" + text: "Production" + text: "Overwriting client IPs" +--- + +import { Code } from "@astrojs/starlight/components"; +import SlotByFramework from "@/components/SlotByFramework"; +import { removeTSCCommentDirectives as removeTypeScriptDirectives } from "@/lib/utils"; +import AstroProxies from "/src/snippets/reference/astro/Proxies.mjs?raw"; +import AstroTrustedIp from "/src/snippets/reference/astro/TrustedIp.mjs?raw"; +import BunProxies from "/src/snippets/reference/bun/Proxies.ts?raw"; +import BunTrustedIp from "/src/snippets/reference/bun/TrustedIp.ts?raw"; +import DenoProxies from "/src/snippets/reference/deno/proxies.ts?raw"; +import DenoTrustedIp from "/src/snippets/reference/deno/trusted-ip.ts?raw"; +import FastifyProxies from "/src/snippets/reference/fastify/proxies.ts?raw"; +import FastifyTrustedIp from "/src/snippets/reference/fastify/trusted-ip.ts?raw"; +import NestProxies from "/src/snippets/reference/nestjs/Proxies.ts?raw"; +import NestTrustedIp from "/src/snippets/reference/nestjs/TrustedIp.ts?raw"; +import NextProxies from "/src/snippets/reference/nextjs/Proxies.ts?raw"; +import NextTrustedIp from "/src/snippets/reference/nextjs/TrustedIp.ts?raw"; +import NodeProxies from "/src/snippets/reference/nodejs/Proxies.ts?raw"; +import NodeTrustedIp from "/src/snippets/reference/nodejs/TrustedIp.ts?raw"; +import NuxtProxies from "@repo/nuxt/server/utils/ProxiesConfig.ts?raw"; +import NuxtTrustedIp from "@repo/nuxt/server/utils/TrustedIp.ts?raw"; +import ReactRouterProxies from "/src/snippets/reference/react-router/proxies.ts?raw"; +import ReactRouterTrustedIp from "/src/snippets/reference/react-router/trusted-ip.ts?raw"; +import RemixProxies from "/src/snippets/reference/remix/Proxies.ts?raw"; +import RemixTrustedIp from "/src/snippets/reference/remix/TrustedIp.ts?raw"; +import SveltekitProxies from "/src/snippets/reference/sveltekit/Proxies.ts?raw"; +import SveltekitTrustedIp from "/src/snippets/reference/sveltekit/TrustedIp.ts?raw"; + +
+ +Arcjet needs the public IP address of incoming requests for much of what it does. +By default, +Arcjet uses the IP as a characteristic to differentiate users. +If that doesn’t work correctly, +several good users may be denied access because they cannot be differentiated +from a bad user. +Or a malicious user could get around rate limits by appearing as different +users. +Arcjet also uses the client IP for geolocation and other reflected metadata. + +Finding the correct client IP address is tricky. +How to find that IP depends on the framework you build with, +the platform you deploy to, +and whether there are proxies or similar services in front of it. + +When developing an app locally, +there is no public client IP. +When testing Arcjet, +it is often needed to overwrite the IP. + +## Framework + +Each Arcjet SDK is made for a particular framework and detects the client IP +correctly from incoming requests out of the box. +Some frameworks provide that IP address on the request directly +(such as `request.ip` and `request.requestContext.identity.sourceIp`), +in other cases it can be inferred from headers +(see the next section “[Platform][section-platform]”). + +The found IP may be of a proxy or other service in front of your application. +See the section “[Proxies][section-proxies]” for these cases. + +If no IP is detected in production, +you’ll see a big warning in the logs. +In this case, +if you do know where to find the correct IP address, +you can [overwrite the client IP][section-overwrite-ip]. +But please also [open an issue][arcjet-arcjet-js-issues] so that this bug can +be fixed. + +## Platform + +Arcjet looks at request headers when frameworks do not provide the client IP +directly or when it matches a configured proxy. +Which headers to trust depends on the platform your app runs on. +Arcjet infers whether an app runs on Firebase, Fly, Render, or Vercel +(but not Cloudflare) from the environment. +On other platforms Arcjet looks for common headers. + +The considered [environment variables][arcjet-env-external] and their +corresponding platforms are as follows: + +| Environment variable | Platform | +| ------------------------------------------- | ------------ | +| [`FIREBASE_CONFIG`][google-firebase-config] | **Firebase** | +| [`FLY_APP_NAME`][fly-app-name] | **Fly** | +| [`RENDER`][render-render] | **Render** | +| [`VERCEL`][vercel-vercel] | **Vercel** | + +The considered headers, their formats, and their corresponding platforms are as +follows: + +| Header | Format | Platforms | +| --------------------------------------------------------- | ------------------- | --------------------------------- | +| [`cf-connecting-ipv6`][cloudflare-cf-connecting-ipv6] | IPv6 | **Cloudflare** | +| [`cf-connecting-ip`][cloudflare-cf-connecting-ip] | IP | **Cloudflare** | +| [`do-connecting-ip`][digitalocean-do-connecting-ip] | IP | Unknown | +| [`fastly-client-ip`][fastly-client-ip] | IP | Unknown | +| [`fly-client-ip`][fly-client-ip] | IP | **Fly** | +| `forwarded-for` | IP | Unknown | +| [`forwarded`][mdn-forwarded] | RFC 7239 | Unknown | +| `true-client-ip` | IP | **Render**, unknown | +| [`x-appengine-user-ip`][google-app-engine-user-ip] | IP | Unknown | +| `x-client-ip` | IP | Unknown | +| `x-cluster-client-ip` | IP | Unknown | +| `x-fah-client-ip` | IP | **Firebase** | +| [`x-forwarded-for`][mdn-x-forwarded-for] | Comma-separated IPs | **Firebase**, **Vercel**, unknown | +| `x-forwarded` | IP | Unknown | +| `x-real-ip` | IP | **Vercel**, unknown | +| [`x-vercel-forwarded-for`][vercel-x-vercel-forwarded-for] | Comma-separated IPs | **Vercel** | + +When using platforms not listed here and you know which header to trust, +you can [overwrite the client IP][section-overwrite-ip]. +It is important to trust this header because headers can be set by end users. +If your platform does not set for example `x-client-ip` but a malicious user +sets it, +that untrusted value would be used. + +If you use a platform not listed here which can be detected from the +environment and sets certain headers, +please [open an issue][arcjet-arcjet-js-issues] so that trusted support can be +added for it. + +## Proxies + +When you put services like proxies or load balancers in front of your +application, +the IP address that Arcjet finds will be that of the last proxy. + +Well-behaving services will use an `x-forwarded-for` or `forwarded` header to +forward the IP addresses that connect to them. + +Because malicious users can also set headers, +the left-most value in such headers cannot be trusted. +But the right-most value of these well-behaving services _can_ be trusted. +And when that IP belongs to another service that you trust, +the one before it can be used. + +To illustrate, +when you put a service like Cloudflare in front of your application, +and know that it sets headers correctly, +and know which IP addresses belong to it, +after verifying that the IP belongs to it, +you trust the IP _before_ it. + +Setting `proxies` works as follows: + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+You can configure Arcjet to trust particular IP addresses.
+See “[Concepts: Client IP](/concepts/client-ip)” for more info.
## Protect
diff --git a/src/content/docs/reference/bun.mdx b/src/content/docs/reference/bun.mdx
index 1925f1f4..655943f7 100644
--- a/src/content/docs/reference/bun.mdx
+++ b/src/content/docs/reference/bun.mdx
@@ -19,7 +19,6 @@ import MultipleRulesTS from "/src/snippets/reference/bun/MultipleRules.ts?raw";
import MultipleRulesJS from "/src/snippets/reference/bun/MultipleRules.js?raw";
import LoggerTS from "/src/snippets/reference/bun/Logger.ts?raw";
import LoggerJS from "/src/snippets/reference/bun/Logger.js?raw";
-import ProxiesTS from "/src/snippets/reference/bun/Proxies.ts?raw";
import ProtectTS from "/src/snippets/reference/bun/Protect.ts?raw";
import ProtectJS from "/src/snippets/reference/bun/Protect.js?raw";
import DecisionLogTS from "/src/snippets/reference/bun/DecisionLog.ts?raw";
@@ -107,8 +106,18 @@ The optional fields are:
- `proxies` (`string[]`) - A list of one or more trusted proxies. These
addresses will be excluded when Arcjet is determining the client IP address.
This is useful if you are behind a load balancer or proxy that sets the client
- IP address in a header. See [Load balancers &
- proxies](#load-balancers--proxies) below for an example.
+ IP address in a header.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+- `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you
+ trust (such as `x-fah-client-ip`).
+ This value is _preferred_ over IP addresses provided by the framework and IP
+ addresses found in other headers based on the platform,
+ in both development and production.
+ It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such
+ as `x-forwarded-for`).
+ It can contain IPv4 or IPv6 addresses.
+ Proxies are filtered out.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+You can configure Arcjet to trust particular IP addresses.
+See “[Concepts: Client IP](/concepts/client-ip)” for more info.
## Protect
diff --git a/src/content/docs/reference/nestjs.mdx b/src/content/docs/reference/nestjs.mdx
index 3077ffae..68099333 100644
--- a/src/content/docs/reference/nestjs.mdx
+++ b/src/content/docs/reference/nestjs.mdx
@@ -13,7 +13,6 @@ import WhatIsArcjet from "/src/components/WhatIsArcjet.astro";
import ErrorLoggingTS from "/src/snippets/reference/nestjs/ErrorLogging.ts?raw";
import ErrorUserAgentTS from "/src/snippets/reference/nestjs/ErrorUserAgent.ts?raw";
import LoggerTS from "/src/snippets/reference/nestjs/ClientLogger.ts?raw";
-import ProxiesTS from "/src/snippets/reference/nestjs/Proxies.ts?raw";
import ConfigurationTS from "/src/snippets/reference/nestjs/Configuration.ts?raw";
import IPLocationTS from "/src/snippets/reference/nestjs/IPLocation.ts?raw";
import NodeVersions from "/src/snippets/reference/node-versions.mdx";
@@ -84,8 +83,18 @@ The optional fields are:
- `proxies` (`string[]`) - A list of one or more trusted proxies. These
addresses will be excluded when Arcjet is determining the client IP address.
This is useful if you are behind a load balancer or proxy that sets the client
- IP address in a header. See [Load balancers &
- proxies](#load-balancers--proxies) below for an example.
+ IP address in a header.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+- `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you
+ trust (such as `x-fah-client-ip`).
+ This value is _preferred_ over IP addresses provided by the framework and IP
+ addresses found in other headers based on the platform,
+ in both development and production.
+ It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such
+ as `x-forwarded-for`).
+ It can contain IPv4 or IPv6 addresses.
+ Proxies are filtered out.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
@@ -138,37 +147,8 @@ controllers.
If your application is behind a load balancer, Arcjet will only see the IP
address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the
-real client IP address plus a list of proxies that the request has passed
-through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the
-client, so you should only trust it if you are sure that the load balancer is
-setting it correctly. See [the MDN
-docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)
-for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header
-by setting the `proxies` field in the configuration. This should be a list of
-the IP addresses or the CIDR range of your load balancers to be removed, so
-that the last IP address in the list is the real client IP address.
-
-#### Example
-
-For example, if the load balancer is at `100.100.100.100` and the client IP
-address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```http
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use
-`192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-
+You can configure Arcjet to trust particular IP addresses.
+See “[Concepts: Client IP](/concepts/client-ip)” for more info.
## Decision
diff --git a/src/content/docs/reference/nextjs.mdx b/src/content/docs/reference/nextjs.mdx
index 6fef7800..02292dc9 100644
--- a/src/content/docs/reference/nextjs.mdx
+++ b/src/content/docs/reference/nextjs.mdx
@@ -44,7 +44,6 @@ import ProtectAppJS from "/src/snippets/reference/nextjs/ProtectApp.js?raw";
import ProtectAppTS from "/src/snippets/reference/nextjs/ProtectApp.ts?raw";
import ProtectPagesJS from "/src/snippets/reference/nextjs/ProtectPages.js?raw";
import ProtectPagesTS from "/src/snippets/reference/nextjs/ProtectPages.ts?raw";
-import ProxiesTS from "/src/snippets/reference/nextjs/Proxies.ts?raw";
import RuleModesJS from "/src/snippets/reference/nextjs/RuleModes.js?raw";
import RuleModesTS from "/src/snippets/reference/nextjs/RuleModes.ts?raw";
import ServerAction from "/src/snippets/reference/nextjs/ServerAction.tsx?raw";
@@ -155,8 +154,18 @@ The optional fields are:
- `proxies` (`string[]`) - A list of one or more trusted proxies. These
addresses will be excluded when Arcjet is determining the client IP address.
This is useful if you are behind a load balancer or proxy that sets the client
- IP address in a header. See [Load balancers &
- proxies](#load-balancers--proxies) below for an example.
+ IP address in a header.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+- `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you
+ trust (such as `x-fah-client-ip`).
+ This value is _preferred_ over IP addresses provided by the framework and IP
+ addresses found in other headers based on the platform,
+ in both development and production.
+ It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such
+ as `x-forwarded-for`).
+ It can contain IPv4 or IPv6 addresses.
+ Proxies are filtered out.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+You can configure Arcjet to trust particular IP addresses.
+See “[Concepts: Client IP](/concepts/client-ip)” for more info.
## Protect
diff --git a/src/content/docs/reference/nodejs.mdx b/src/content/docs/reference/nodejs.mdx
index 9903b246..326c9a1c 100644
--- a/src/content/docs/reference/nodejs.mdx
+++ b/src/content/docs/reference/nodejs.mdx
@@ -13,7 +13,6 @@ import ProtectTS from "/src/snippets/reference/nodejs/Protect.ts?raw";
import ProtectJS from "/src/snippets/reference/nodejs/Protect.js?raw";
import LoggerTS from "/src/snippets/reference/nodejs/Logger.ts?raw";
import LoggerJS from "/src/snippets/reference/nodejs/Logger.js?raw";
-import ProxiesTS from "/src/snippets/reference/nodejs/Proxies.ts?raw";
import IPLocationTS from "/src/snippets/reference/nodejs/IPLocation.ts?raw";
import IPLocationJS from "/src/snippets/reference/nodejs/IPLocation.js?raw";
import WithRuleTS from "/src/snippets/reference/nodejs/WithRule.ts?raw";
@@ -94,8 +93,18 @@ The optional fields are:
- `proxies` (`string[]`) - A list of one or more trusted proxies. These
addresses will be excluded when Arcjet is determining the client IP address.
This is useful if you are behind a load balancer or proxy that sets the client
- IP address in a header. See [Load balancers &
- proxies](#load-balancers--proxies) below for an example.
+ IP address in a header.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+- `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you
+ trust (such as `x-fah-client-ip`).
+ This value is _preferred_ over IP addresses provided by the framework and IP
+ addresses found in other headers based on the platform,
+ in both development and production.
+ It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such
+ as `x-forwarded-for`).
+ It can contain IPv4 or IPv6 addresses.
+ Proxies are filtered out.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+You can configure Arcjet to trust particular IP addresses.
+See “[Concepts: Client IP](/concepts/client-ip)” for more info.
## Protect
diff --git a/src/content/docs/reference/nuxt.mdx b/src/content/docs/reference/nuxt.mdx
index 9587bce0..4c7dffd1 100644
--- a/src/content/docs/reference/nuxt.mdx
+++ b/src/content/docs/reference/nuxt.mdx
@@ -20,8 +20,6 @@ import RuleModesConfigTS from "@repo/nuxt/server/utils/RulesModesConfig.ts?raw";
import RuleModesConfigJS from "@repo/nuxt/server/utils/RulesModesConfig.js?raw";
import MultipleRulesTS from "@repo/nuxt/server/utils/MultipleRules.ts?raw";
import MultipleRulesJS from "@repo/nuxt/server/utils/MultipleRules.js?raw";
-import ProxiesConfigTS from "@repo/nuxt/server/utils/ProxiesConfig.ts?raw";
-import ProxiesConfigJS from "@repo/nuxt/server/utils/ProxiesConfig.js?raw";
import ServerRoutesTS from "@repo/nuxt/server/routes/ServerRoutes.get.ts?raw";
import ServerRoutesJS from "@repo/nuxt/server/routes/ServerRoutes.get.js?raw";
import ServerAPIRoutesTS from "@repo/nuxt/server/api/ServerAPIRoutes.post.ts?raw";
@@ -161,8 +159,18 @@ The optional fields are:
- `proxies` (`string[]`) - A list of one or more trusted proxies. These
addresses will be excluded when Arcjet is determining the client IP address.
This is useful if you are behind a load balancer or proxy that sets the client
- IP address in a header. See [Load balancers &
- proxies](#load-balancers--proxies) below for an example.
+ IP address in a header.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+- `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you
+ trust (such as `x-fah-client-ip`).
+ This value is _preferred_ over IP addresses provided by the framework and IP
+ addresses found in other headers based on the platform,
+ in both development and production.
+ It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such
+ as `x-forwarded-for`).
+ It can contain IPv4 or IPv6 addresses.
+ Proxies are filtered out.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
### Single instance
@@ -249,52 +257,8 @@ explicitly in `nuxt.config.ts`.
If your application is behind a load balancer, Arcjet will only see the IP
address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the
-real client IP address plus a list of proxies that the request has passed
-through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the
-client, so you should only trust it if you are sure that the load balancer is
-setting it correctly. See [the MDN
-docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)
-for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header
-by setting the `proxies` field in the configuration. This should be a list of
-the IP addresses or the CIDR range of your load balancers to be removed, so that
-the last IP address in the list is the real client IP address.
-
-#### Example
-
-For example, if the load balancer is at `100.100.100.100` and the client IP
-address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```http
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use
-`192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-
-
-
+You can configure Arcjet to trust particular IP addresses.
+See “[Concepts: Client IP](/concepts/client-ip)” for more info.
## Protect
diff --git a/src/content/docs/reference/sveltekit.mdx b/src/content/docs/reference/sveltekit.mdx
index 3c5acfbd..0be73acc 100644
--- a/src/content/docs/reference/sveltekit.mdx
+++ b/src/content/docs/reference/sveltekit.mdx
@@ -21,7 +21,6 @@ import ProtectTS from "/src/snippets/reference/sveltekit/Protect.ts?raw";
import ProtectJS from "/src/snippets/reference/sveltekit/Protect.js?raw";
import LoggerTS from "/src/snippets/reference/sveltekit/Logger.ts?raw";
import LoggerJS from "/src/snippets/reference/sveltekit/Logger.js?raw";
-import ProxiesTS from "/src/snippets/reference/sveltekit/Proxies.ts?raw";
import DecisionLogTS from "/src/snippets/reference/sveltekit/DecisionLog.ts?raw";
import DecisionLogJS from "/src/snippets/reference/sveltekit/DecisionLog.js?raw";
import ErrorLoggingTS from "/src/snippets/reference/sveltekit/ErrorLogging.ts?raw";
@@ -127,8 +126,18 @@ The optional fields are:
- `proxies` (`string[]`) - A list of one or more trusted proxies. These
addresses will be excluded when Arcjet is determining the client IP address.
This is useful if you are behind a load balancer or proxy that sets the client
- IP address in a header. See [Load balancers &
- proxies](#load-balancers--proxies) below for an example.
+ IP address in a header.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+- `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you
+ trust (such as `x-fah-client-ip`).
+ This value is _preferred_ over IP addresses provided by the framework and IP
+ addresses found in other headers based on the platform,
+ in both development and production.
+ It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such
+ as `x-forwarded-for`).
+ It can contain IPv4 or IPv6 addresses.
+ Proxies are filtered out.
+ See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+You can configure Arcjet to trust particular IP addresses.
+See “[Concepts: Client IP](/concepts/client-ip)” for more info.
## Protect
diff --git a/src/content/docs/troubleshooting.mdx b/src/content/docs/troubleshooting.mdx
index a3ed86c5..9eaa978a 100644
--- a/src/content/docs/troubleshooting.mdx
+++ b/src/content/docs/troubleshooting.mdx
@@ -85,20 +85,12 @@ When you deploy your app next, Arcjet should not trigger on this route.
Arcjet's [IP geolocation](/blueprints/ip-geolocation) and [VPN & proxy
detection](/blueprints/vpn-proxy-detection) features require a real IP address
-to work. In local development, Arcjet defaults to `127.0.0.1` so the IP analysis
-metadata will be empty.
-
-You can set the IP address to a real public IP by overriding the IP address
-field (`ip`) in the `request` object that is passed to the Arcjet `protect`
-function.
-
-```ts
-// Override the IP address in the request object if `ip` is provided. You could
-// set this using an environment variable or some other method to ensure it is
-// only set in development.
-//const ip = "8.8.8.8"; // Google's public DNS server
-const decision = await aj.protect(ip ? { ...req, ip } : req);
-```
+to work.
+When you are developing your app locally,
+there is no public IP.
+In that case the IP analysis metadata will be empty.
+In development you can pass an `x-arcjet-xxx` header.
+See “[Concepts: Client IP](/concepts/client-ip)” for more info.
## Common errors
@@ -165,6 +157,8 @@ development mode. If this appears in production, check that
[`ARCJET_ENV`](/environment#arcjet-env) is not incorrectly set to
`development`.
+See also “[Concepts: Client IP](/concepts/client-ip)” for more info.
+
### generateFingerprint: ip is empty / [failed_precondition] client IP not provided
Arcjet normally detects when it is running in a local environment and uses a
@@ -186,6 +180,8 @@ each request is coming from. If the IP address is not provided, or it is running
in production and a private/internal address is provided, then Arcjet will show
this error.
+See also “[Concepts: Client IP](/concepts/client-ip)” for more info.
+
### [failed_precondition] request details failed validation
Arcjet expects certain fields to exist on the object used to analyze each
diff --git a/src/lib/sidebars.ts b/src/lib/sidebars.ts
index d8874a26..30e8a601 100644
--- a/src/lib/sidebars.ts
+++ b/src/lib/sidebars.ts
@@ -322,6 +322,16 @@ export const main = [
},
],
},
+ {
+ label: "Concepts",
+ collapsed: false,
+ items: [
+ {
+ label: "Client IP",
+ link: "/concepts/client-ip",
+ },
+ ],
+ },
{
label: "Advanced",
collapsed: false,
diff --git a/src/snippets/ip/proxies.ts b/src/snippets/ip/proxies.ts
index 78884e9d..5de5758d 100644
--- a/src/snippets/ip/proxies.ts
+++ b/src/snippets/ip/proxies.ts
@@ -1,14 +1,14 @@
-import ip from "@arcjet/ip";
+import { findIp } from "@arcjet/ip";
// Some Request-like object, such as node's `http.IncomingMessage`, `Request` or
// Next.js' `NextRequest`
const request = new Request("/your-route");
// You can also pass a list of trusted proxies to ignore
-const proxyExcludedPublicIp = ip(request, {
+const proxyExcludedPublicIp = findIp(request, {
proxies: [
- "100.100.100.100", // A single IP
- "100.100.100.0/24", // A CIDR for the range
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
],
});
console.log(proxyExcludedPublicIp);
diff --git a/src/snippets/reference/astro/Proxies.mjs b/src/snippets/reference/astro/Proxies.mjs
index 71f72eab..78c58f21 100644
--- a/src/snippets/reference/astro/Proxies.mjs
+++ b/src/snippets/reference/astro/Proxies.mjs
@@ -1,22 +1,18 @@
// @ts-check
-import { defineConfig } from "astro/config";
-import node from "@astrojs/node";
import arcjet from "@arcjet/astro";
+import node from "@astrojs/node";
+import { defineConfig } from "astro/config";
export default defineConfig({
- adapter: node({
- mode: "standalone",
- }),
- env: {
- validateSecrets: true,
- },
+ adapter: node({ mode: "standalone" }),
+ env: { validateSecrets: true },
integrations: [
arcjet({
- rules: [],
proxies: [
- "100.100.100.100", // A single IP
- "100.100.100.0/24", // A CIDR for the range
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
],
+ rules: [],
}),
],
});
diff --git a/src/snippets/reference/astro/TrustedIp.mjs b/src/snippets/reference/astro/TrustedIp.mjs
new file mode 100644
index 00000000..4a406f68
--- /dev/null
+++ b/src/snippets/reference/astro/TrustedIp.mjs
@@ -0,0 +1,18 @@
+// @ts-check
+import arcjet, { slidingWindow } from "@arcjet/astro";
+import node from "@astrojs/node";
+import { defineConfig } from "astro/config";
+
+export default defineConfig({
+ adapter: node({ mode: "standalone" }),
+ env: { validateSecrets: true },
+ integrations: [
+ arcjet({
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // @ts-expect-error: TODO does not yet exist.
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ trustedIpHeader: "x-my-ip",
+ }),
+ ],
+});
diff --git a/src/snippets/reference/bun/Proxies.ts b/src/snippets/reference/bun/Proxies.ts
index f4160e66..c4f85c1b 100644
--- a/src/snippets/reference/bun/Proxies.ts
+++ b/src/snippets/reference/bun/Proxies.ts
@@ -1,11 +1,11 @@
-import arcjet from "@arcjet/bun";
+import arcjetBun from "@arcjet/bun";
import { env } from "bun";
-const aj = arcjet({
+const arcjet = arcjetBun({
key: env.ARCJET_KEY!,
- rules: [],
proxies: [
- "100.100.100.100", // A single IP
- "100.100.100.0/24", // A CIDR for the range
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
],
+ rules: [],
});
diff --git a/src/snippets/reference/bun/TrustedIp.ts b/src/snippets/reference/bun/TrustedIp.ts
new file mode 100644
index 00000000..944202cd
--- /dev/null
+++ b/src/snippets/reference/bun/TrustedIp.ts
@@ -0,0 +1,11 @@
+import arcjetBun, { slidingWindow } from "@arcjet/bun";
+import { env } from "bun";
+
+const arcjet = arcjetBun({
+ key: env.ARCJET_KEY!,
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // @ts-expect-error: TODO does not yet exist.
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ trustedIpHeader: "x-my-ip",
+});
diff --git a/src/snippets/reference/deno/proxies.ts b/src/snippets/reference/deno/proxies.ts
new file mode 100644
index 00000000..39ef66a7
--- /dev/null
+++ b/src/snippets/reference/deno/proxies.ts
@@ -0,0 +1,11 @@
+import "jsr:@std/dotenv/load";
+import arcjetDeno from "@arcjet/deno";
+
+const arcjet = arcjetDeno({
+ key: Deno.env.get("ARCJET_KEY")!,
+ proxies: [
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
+ ],
+ rules: [],
+});
diff --git a/src/snippets/reference/deno/trusted-ip.ts b/src/snippets/reference/deno/trusted-ip.ts
new file mode 100644
index 00000000..561a5869
--- /dev/null
+++ b/src/snippets/reference/deno/trusted-ip.ts
@@ -0,0 +1,11 @@
+import "jsr:@std/dotenv/load";
+import arcjetDeno, { slidingWindow } from "@arcjet/deno";
+
+const arcjet = arcjetDeno({
+ key: Deno.env.get("ARCJET_KEY")!,
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // @ts-expect-error: TODO does not yet exist.
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ trustedIpHeader: "x-my-ip",
+});
diff --git a/src/snippets/reference/fastify/proxies.ts b/src/snippets/reference/fastify/proxies.ts
new file mode 100644
index 00000000..a1de733c
--- /dev/null
+++ b/src/snippets/reference/fastify/proxies.ts
@@ -0,0 +1,10 @@
+import arcjetFastify from "@arcjet/fastify";
+
+const arcjet = arcjetFastify({
+ key: process.env.ARCJET_KEY!,
+ proxies: [
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
+ ],
+ rules: [],
+});
diff --git a/src/snippets/reference/fastify/trusted-ip.ts b/src/snippets/reference/fastify/trusted-ip.ts
new file mode 100644
index 00000000..e311bcfc
--- /dev/null
+++ b/src/snippets/reference/fastify/trusted-ip.ts
@@ -0,0 +1,10 @@
+import arcjetFastify, { slidingWindow } from "@arcjet/fastify";
+
+const arcjet = arcjetFastify({
+ key: process.env.ARCJET_KEY!,
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ // @ts-expect-error: TODO does not yet exist.
+ trustedIpHeader: "x-my-ip",
+});
diff --git a/src/snippets/reference/nestjs/Proxies.ts b/src/snippets/reference/nestjs/Proxies.ts
index 17f3d6d5..e5ed099d 100644
--- a/src/snippets/reference/nestjs/Proxies.ts
+++ b/src/snippets/reference/nestjs/Proxies.ts
@@ -5,19 +5,19 @@ import { ConfigModule } from "@nestjs/config";
@Module({
imports: [
ConfigModule.forRoot({
- isGlobal: true,
envFilePath: ".env.local",
+ isGlobal: true,
}),
ArcjetModule.forRoot({
isGlobal: true,
key: process.env.ARCJET_KEY!,
+ proxies: [
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
+ ],
rules: [
// Rules set here will apply to every request
],
- proxies: [
- "100.100.100.100", // A single IP
- "100.100.100.0/24", // A CIDR for the range
- ],
}),
// ... other modules
],
diff --git a/src/snippets/reference/nestjs/TrustedIp.ts b/src/snippets/reference/nestjs/TrustedIp.ts
new file mode 100644
index 00000000..c816679f
--- /dev/null
+++ b/src/snippets/reference/nestjs/TrustedIp.ts
@@ -0,0 +1,23 @@
+import { ArcjetModule, slidingWindow } from "@arcjet/nest";
+import { Module } from "@nestjs/common";
+import { ConfigModule } from "@nestjs/config";
+
+@Module({
+ imports: [
+ ConfigModule.forRoot({
+ envFilePath: ".env.local",
+ isGlobal: true,
+ }),
+ ArcjetModule.forRoot({
+ isGlobal: true,
+ key: process.env.ARCJET_KEY!,
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // @ts-expect-error: TODO does not yet exist.
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ trustedIpHeader: "x-my-ip",
+ }),
+ // ... other modules
+ ],
+})
+export class AppModule {}
diff --git a/src/snippets/reference/nextjs/Proxies.ts b/src/snippets/reference/nextjs/Proxies.ts
index a4dc33d8..9346f276 100644
--- a/src/snippets/reference/nextjs/Proxies.ts
+++ b/src/snippets/reference/nextjs/Proxies.ts
@@ -1,10 +1,10 @@
-import arcjet from "@arcjet/next";
+import arcjetNext from "@arcjet/next";
-const aj = arcjet({
+const arcjet = arcjetNext({
key: process.env.ARCJET_KEY!,
- rules: [],
proxies: [
- "100.100.100.100", // A single IP
- "100.100.100.0/24", // A CIDR for the range
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
],
+ rules: [],
});
diff --git a/src/snippets/reference/nextjs/TrustedIp.ts b/src/snippets/reference/nextjs/TrustedIp.ts
new file mode 100644
index 00000000..b6d09885
--- /dev/null
+++ b/src/snippets/reference/nextjs/TrustedIp.ts
@@ -0,0 +1,10 @@
+import arcjetNext, { slidingWindow } from "@arcjet/next";
+
+const arcjet = arcjetNext({
+ key: process.env.ARCJET_KEY!,
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // @ts-expect-error: TODO does not yet exist.
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ trustedIpHeader: "x-my-ip",
+});
diff --git a/src/snippets/reference/nodejs/Proxies.ts b/src/snippets/reference/nodejs/Proxies.ts
index e500ebc2..9a5b007e 100644
--- a/src/snippets/reference/nodejs/Proxies.ts
+++ b/src/snippets/reference/nodejs/Proxies.ts
@@ -1,10 +1,10 @@
-import arcjet from "@arcjet/node";
+import arcjetNode from "@arcjet/node";
-const aj = arcjet({
+const arcjet = arcjetNode({
key: process.env.ARCJET_KEY!,
- rules: [],
proxies: [
- "100.100.100.100", // A single IP
- "100.100.100.0/24", // A CIDR for the range
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
],
+ rules: [],
});
diff --git a/src/snippets/reference/nodejs/TrustedIp.ts b/src/snippets/reference/nodejs/TrustedIp.ts
new file mode 100644
index 00000000..0d986938
--- /dev/null
+++ b/src/snippets/reference/nodejs/TrustedIp.ts
@@ -0,0 +1,10 @@
+import arcjetNode, { slidingWindow } from "@arcjet/node";
+
+const arcjet = arcjetNode({
+ key: process.env.ARCJET_KEY!,
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // @ts-expect-error: TODO does not yet exist.
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ trustedIpHeader: "x-my-ip",
+});
diff --git a/src/snippets/reference/react-router/proxies.ts b/src/snippets/reference/react-router/proxies.ts
new file mode 100644
index 00000000..f3a66b81
--- /dev/null
+++ b/src/snippets/reference/react-router/proxies.ts
@@ -0,0 +1,10 @@
+import arcjetReactRouter from "@arcjet/react-router";
+
+const arcjet = arcjetReactRouter({
+ key: process.env.ARCJET_KEY!,
+ proxies: [
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
+ ],
+ rules: [],
+});
diff --git a/src/snippets/reference/react-router/trusted-ip.ts b/src/snippets/reference/react-router/trusted-ip.ts
new file mode 100644
index 00000000..0ece8900
--- /dev/null
+++ b/src/snippets/reference/react-router/trusted-ip.ts
@@ -0,0 +1,10 @@
+import arcjetReactRouter, { slidingWindow } from "@arcjet/react-router";
+
+const arcjet = arcjetReactRouter({
+ key: process.env.ARCJET_KEY!,
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // @ts-expect-error: TODO does not yet exist.
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ trustedIpHeader: "x-my-ip",
+});
diff --git a/src/snippets/reference/remix/Proxies.ts b/src/snippets/reference/remix/Proxies.ts
index 378116dc..d4e02a9e 100644
--- a/src/snippets/reference/remix/Proxies.ts
+++ b/src/snippets/reference/remix/Proxies.ts
@@ -1,10 +1,10 @@
-import arcjet from "@arcjet/remix";
+import arcjetRemix from "@arcjet/remix";
-const aj = arcjet({
+const arcjet = arcjetRemix({
key: process.env.ARCJET_KEY!,
- rules: [],
proxies: [
- "100.100.100.100", // A single IP
- "100.100.100.0/24", // A CIDR for the range
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
],
+ rules: [],
});
diff --git a/src/snippets/reference/remix/TrustedIp.ts b/src/snippets/reference/remix/TrustedIp.ts
new file mode 100644
index 00000000..f8e9ea69
--- /dev/null
+++ b/src/snippets/reference/remix/TrustedIp.ts
@@ -0,0 +1,10 @@
+import arcjetRemix, { slidingWindow } from "@arcjet/remix";
+
+const arcjet = arcjetRemix({
+ key: process.env.ARCJET_KEY!,
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // @ts-expect-error: TODO does not yet exist.
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ trustedIpHeader: "x-my-ip",
+});
diff --git a/src/snippets/reference/sveltekit/Proxies.ts b/src/snippets/reference/sveltekit/Proxies.ts
index 7619a199..863dc7df 100644
--- a/src/snippets/reference/sveltekit/Proxies.ts
+++ b/src/snippets/reference/sveltekit/Proxies.ts
@@ -1,11 +1,11 @@
import { env } from "$env/dynamic/private";
-import arcjet from "@arcjet/sveltekit";
+import arcjetSveltekit from "@arcjet/sveltekit";
-const aj = arcjet({
+const arcjet = arcjetSveltekit({
key: env.ARCJET_KEY!,
- rules: [],
proxies: [
- "100.100.100.100", // A single IP
- "100.100.100.0/24", // A CIDR for the range
+ "76.76.21.21", // An IP address.
+ "103.21.244.0/22", // A CIDR range of IP addresses.
],
+ rules: [],
});
diff --git a/src/snippets/reference/sveltekit/TrustedIp.ts b/src/snippets/reference/sveltekit/TrustedIp.ts
new file mode 100644
index 00000000..44c5ded1
--- /dev/null
+++ b/src/snippets/reference/sveltekit/TrustedIp.ts
@@ -0,0 +1,11 @@
+import { env } from "$env/dynamic/private";
+import arcjetSveltekit, { slidingWindow } from "@arcjet/sveltekit";
+
+const arcjet = arcjetSveltekit({
+ key: env.ARCJET_KEY!,
+ // To illustrate, allow 3 requests per minute per IP address.
+ rules: [slidingWindow({ interval: 60, max: 3, mode: "LIVE" })],
+ // @ts-expect-error: TODO does not yet exist.
+ // Assumes requests will have an `x-my-ip` header that you trust:
+ trustedIpHeader: "x-my-ip",
+});
diff --git a/tests/llms-txt.test.ts-snapshots/reference-astro-chromium-linux.md b/tests/llms-txt.test.ts-snapshots/reference-astro-chromium-linux.md
index fd4480fa..fb7fafb6 100644
--- a/tests/llms-txt.test.ts-snapshots/reference-astro-chromium-linux.md
+++ b/tests/llms-txt.test.ts-snapshots/reference-astro-chromium-linux.md
@@ -104,7 +104,8 @@ The required fields are:
The optional fields are:
* `characteristics` (`string[]`) - A list of [characteristics](/fingerprints#built-in-characteristics) to be used to uniquely identify clients.
-* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See [Load balancers & proxies](#load-balancers--proxies) below for an example.
+* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+* `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you trust (such as `x-fah-client-ip`). This value is _preferred_ over IP addresses provided by the framework and IP addresses found in other headers based on the platform, in both development and production. It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such as `x-forwarded-for`). It can contain IPv4 or IPv6 addresses. Proxies are filtered out. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
### Single instance
@@ -168,34 +169,7 @@ The Arcjet Astro SDK uses several environment variables to configure its behavio
[Section titled “Load balancers & proxies”](#load-balancers--proxies)
-If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the real client IP address plus a list of proxies that the request has passed through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the client, so you should only trust it if you are sure that the load balancer is setting it correctly. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header by setting the `proxies` field in the configuration. This should be a list of the IP addresses or the CIDR range of your load balancers to be removed, so that the last IP address in the list is the real client IP address.
-
-#### Example
-
-[Section titled “Example”](#example)
-
-For example, if the load balancer is at `100.100.100.100` and the client IP address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use `192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-astro.config.mjs
-
-```
-1import { defineConfig } from "astro/config";2import node from "@astrojs/node";3import arcjet from "@arcjet/astro";4
-5export default defineConfig({6 adapter: node({7 mode: "standalone",8 }),9 env: {10 validateSecrets: true,11 },12 integrations: [13 arcjet({14 rules: [],15 proxies: [16 "100.100.100.100", // A single IP17 "100.100.100.0/24", // A CIDR for the range18 ],19 }),20 ],21});
-```
+If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address. You can configure Arcjet to trust particular IP addresses. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
Protect
-------
@@ -524,7 +498,7 @@ The following are available on all pricing plans:
#### Example
-[Section titled “Example”](#example-1)
+[Section titled “Example”](#example)
astro.config.mjs
diff --git a/tests/llms-txt.test.ts-snapshots/reference-bun-chromium-linux.md b/tests/llms-txt.test.ts-snapshots/reference-bun-chromium-linux.md
index e066c109..aa15a03e 100644
--- a/tests/llms-txt.test.ts-snapshots/reference-bun-chromium-linux.md
+++ b/tests/llms-txt.test.ts-snapshots/reference-bun-chromium-linux.md
@@ -53,7 +53,8 @@ The required fields are:
The optional fields are:
* `characteristics` (`string[]`) - A list of [characteristics](/fingerprints#built-in-characteristics) to be used to uniquely identify clients.
-* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See [Load balancers & proxies](#load-balancers--proxies) below for an example.
+* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+* `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you trust (such as `x-fah-client-ip`). This value is _preferred_ over IP addresses provided by the framework and IP addresses found in other headers based on the platform, in both development and production. It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such as `x-forwarded-for`). It can contain IPv4 or IPv6 addresses. Proxies are filtered out. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
* [TS](#tab-panel-XXX)
* [JS](#tab-panel-XXX)
@@ -173,32 +174,7 @@ index.js
[Section titled “Load balancers & proxies”](#load-balancers--proxies)
-If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the real client IP address plus a list of proxies that the request has passed through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the client, so you should only trust it if you are sure that the load balancer is setting it correctly. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header by setting the `proxies` field in the configuration. This should be a list of the IP addresses or the CIDR range of your load balancers to be removed, so that the last IP address in the list is the real client IP address.
-
-#### Example
-
-[Section titled “Example”](#example)
-
-For example, if the load balancer is at `100.100.100.100` and the client IP address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use `192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-```
-1import arcjet from "@arcjet/bun";2import { env } from "bun";3
-4const aj = arcjet({5 key: env.ARCJET_KEY!,6 rules: [],7 proxies: [8 "100.100.100.100", // A single IP9 "100.100.100.0/24", // A CIDR for the range10 ],11});
-```
+If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address. You can configure Arcjet to trust particular IP addresses. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
Protect
-------
diff --git a/tests/llms-txt.test.ts-snapshots/reference-nestjs-chromium-linux.md b/tests/llms-txt.test.ts-snapshots/reference-nestjs-chromium-linux.md
index 7ced727c..6ff7a9a2 100644
--- a/tests/llms-txt.test.ts-snapshots/reference-nestjs-chromium-linux.md
+++ b/tests/llms-txt.test.ts-snapshots/reference-nestjs-chromium-linux.md
@@ -64,7 +64,8 @@ The required fields are:
The optional fields are:
* `characteristics` (`string[]`) - A list of [characteristics](/fingerprints#built-in-characteristics) to be used to uniquely identify clients.
-* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See [Load balancers & proxies](#load-balancers--proxies) below for an example.
+* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+* `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you trust (such as `x-fah-client-ip`). This value is _preferred_ over IP addresses provided by the framework and IP addresses found in other headers based on the platform, in both development and production. It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such as `x-forwarded-for`). It can contain IPv4 or IPv6 addresses. Proxies are filtered out. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
src/app.module.ts
@@ -125,32 +126,7 @@ src/app.module.ts
[Section titled “Load balancers & proxies”](#load-balancers--proxies)
-If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the real client IP address plus a list of proxies that the request has passed through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the client, so you should only trust it if you are sure that the load balancer is setting it correctly. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header by setting the `proxies` field in the configuration. This should be a list of the IP addresses or the CIDR range of your load balancers to be removed, so that the last IP address in the list is the real client IP address.
-
-#### Example
-
-[Section titled “Example”](#example)
-
-For example, if the load balancer is at `100.100.100.100` and the client IP address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use `192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-```
-1import { ArcjetModule } from "@arcjet/nest";2import { Module } from "@nestjs/common";3import { ConfigModule } from "@nestjs/config";4
-5@Module({6 imports: [7 ConfigModule.forRoot({8 isGlobal: true,9 envFilePath: ".env.local",10 }),11 ArcjetModule.forRoot({12 isGlobal: true,13 key: process.env.ARCJET_KEY!,14 rules: [15 // Rules set here will apply to every request16 ],17 proxies: [18 "100.100.100.100", // A single IP19 "100.100.100.0/24", // A CIDR for the range20 ],21 }),22 // ... other modules23 ],24})25export class AppModule {}
-```
+If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address. You can configure Arcjet to trust particular IP addresses. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
Decision
--------
@@ -363,7 +339,7 @@ The following are available on all pricing plans:
#### Example
-[Section titled “Example”](#example-1)
+[Section titled “Example”](#example)
```
1import { ARCJET, type ArcjetNest } from "@arcjet/nest";2import {3 Controller,4 Get,5 HttpException,6 HttpStatus,7 Inject,8 Injectable,9 Logger,10 Req,11} from "@nestjs/common";12import type { Request } from "express";13
diff --git a/tests/llms-txt.test.ts-snapshots/reference-nextjs-chromium-linux.md b/tests/llms-txt.test.ts-snapshots/reference-nextjs-chromium-linux.md
index a813e90a..b7547ae8 100644
--- a/tests/llms-txt.test.ts-snapshots/reference-nextjs-chromium-linux.md
+++ b/tests/llms-txt.test.ts-snapshots/reference-nextjs-chromium-linux.md
@@ -82,7 +82,8 @@ The required fields are:
The optional fields are:
* `characteristics` (`string[]`) - A list of [characteristics](/fingerprints#built-in-characteristics) to be used to uniquely identify clients.
-* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See [Load balancers & proxies](#load-balancers--proxies) below for an example.
+* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+* `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you trust (such as `x-fah-client-ip`). This value is _preferred_ over IP addresses provided by the framework and IP addresses found in other headers based on the platform, in both development and production. It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such as `x-forwarded-for`). It can contain IPv4 or IPv6 addresses. Proxies are filtered out. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
* [TS](#tab-panel-XXX)
* [JS](#tab-panel-XXX)
@@ -213,32 +214,7 @@ next.config.js
[Section titled “Load balancers & proxies”](#load-balancers--proxies)
-If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the real client IP address plus a list of proxies that the request has passed through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the client, so you should only trust it if you are sure that the load balancer is setting it correctly. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header by setting the `proxies` field in the configuration. This should be a list of the IP addresses or the CIDR range of your load balancers to be removed, so that the last IP address in the list is the real client IP address.
-
-#### Example
-
-[Section titled “Example”](#example)
-
-For example, if the load balancer is at `100.100.100.100` and the client IP address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use `192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-```
-1import arcjet from "@arcjet/next";2
-3const aj = arcjet({4 key: process.env.ARCJET_KEY!,5 rules: [],6 proxies: [7 "100.100.100.100", // A single IP8 "100.100.100.0/24", // A CIDR for the range9 ],10});
-```
+If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address. You can configure Arcjet to trust particular IP addresses. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
Protect
-------
@@ -637,7 +613,7 @@ The following are available on all pricing plans:
#### Example
-[Section titled “Example”](#example-1)
+[Section titled “Example”](#example)
* [TS (App)](#tab-panel-XXX)
* [TS (Pages)](#tab-panel-XXX)
diff --git a/tests/llms-txt.test.ts-snapshots/reference-nodejs-chromium-linux.md b/tests/llms-txt.test.ts-snapshots/reference-nodejs-chromium-linux.md
index a8237b89..4e7690d3 100644
--- a/tests/llms-txt.test.ts-snapshots/reference-nodejs-chromium-linux.md
+++ b/tests/llms-txt.test.ts-snapshots/reference-nodejs-chromium-linux.md
@@ -62,7 +62,8 @@ The required fields are:
The optional fields are:
* `characteristics` (`string[]`) - A list of [characteristics](/fingerprints#built-in-characteristics) to be used to uniquely identify clients.
-* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See [Load balancers & proxies](#load-balancers--proxies) below for an example.
+* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+* `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you trust (such as `x-fah-client-ip`). This value is _preferred_ over IP addresses provided by the framework and IP addresses found in other headers based on the platform, in both development and production. It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such as `x-forwarded-for`). It can contain IPv4 or IPv6 addresses. Proxies are filtered out. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
* [TS](#tab-panel-XXX)
* [JS](#tab-panel-XXX)
@@ -171,32 +172,7 @@ index.js
[Section titled “Load balancers & proxies”](#load-balancers--proxies)
-If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the real client IP address plus a list of proxies that the request has passed through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the client, so you should only trust it if you are sure that the load balancer is setting it correctly. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header by setting the `proxies` field in the configuration. This should be a list of the IP addresses or the CIDR range of your load balancers to be removed, so that the last IP address in the list is the real client IP address.
-
-#### Example
-
-[Section titled “Example”](#example)
-
-For example, if the load balancer is at `100.100.100.100` and the client IP address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use `192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-```
-1import arcjet from "@arcjet/node";2
-3const aj = arcjet({4 key: process.env.ARCJET_KEY!,5 rules: [],6 proxies: [7 "100.100.100.100", // A single IP8 "100.100.100.0/24", // A CIDR for the range9 ],10});
-```
+If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address. You can configure Arcjet to trust particular IP addresses. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
Protect
-------
@@ -435,7 +411,7 @@ The following are available on all pricing plans:
#### Example
-[Section titled “Example”](#example-1)
+[Section titled “Example”](#example)
* [TS](#tab-panel-XXX)
* [JS](#tab-panel-XXX)
diff --git a/tests/llms-txt.test.ts-snapshots/reference-nuxt-chromium-linux.md b/tests/llms-txt.test.ts-snapshots/reference-nuxt-chromium-linux.md
index 8dd18f4f..0bde66f9 100644
--- a/tests/llms-txt.test.ts-snapshots/reference-nuxt-chromium-linux.md
+++ b/tests/llms-txt.test.ts-snapshots/reference-nuxt-chromium-linux.md
@@ -114,7 +114,8 @@ The required fields are:
The optional fields are:
* `characteristics` (`string[]`) - A list of [characteristics](/fingerprints#built-in-characteristics) to be used to uniquely identify clients.
-* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See [Load balancers & proxies](#load-balancers--proxies) below for an example.
+* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+* `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you trust (such as `x-fah-client-ip`). This value is _preferred_ over IP addresses provided by the framework and IP addresses found in other headers based on the platform, in both development and production. It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such as `x-forwarded-for`). It can contain IPv4 or IPv6 addresses. Proxies are filtered out. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
### Single instance
@@ -192,44 +193,7 @@ The Arcjet Nuxt SDK uses several environment variables to configure its behavior
[Section titled “Load balancers & proxies”](#load-balancers--proxies)
-If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the real client IP address plus a list of proxies that the request has passed through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the client, so you should only trust it if you are sure that the load balancer is setting it correctly. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header by setting the `proxies` field in the configuration. This should be a list of the IP addresses or the CIDR range of your load balancers to be removed, so that the last IP address in the list is the real client IP address.
-
-#### Example
-
-[Section titled “Example”](#example)
-
-For example, if the load balancer is at `100.100.100.100` and the client IP address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use `192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-* [TS](#tab-panel-XXX)
-* [JS](#tab-panel-XXX)
-
-server/utils/arcjet.ts
-
-```
-1import { arcjet as arcjetNuxt } from "#arcjet";2
-3export const arcjet = arcjetNuxt({4 rules: [],5 proxies: [6 "100.100.100.100", // A single IP7 "100.100.100.0/24", // A CIDR for the range8 ],9});
-```
-
-server/utils/arcjet.js
-
-```
-1import { arcjet as arcjetNuxt } from "#arcjet";2
-3export const arcjet = arcjetNuxt({4 rules: [],5 proxies: [6 "100.100.100.100", // A single IP7 "100.100.100.0/24", // A CIDR for the range8 ],9});
-```
+If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address. You can configure Arcjet to trust particular IP addresses. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
Protect
-------
@@ -553,7 +517,7 @@ The following are available on all pricing plans:
#### Example
-[Section titled “Example”](#example-1)
+[Section titled “Example”](#example)
* [TS](#tab-panel-XXX)
* [JS](#tab-panel-XXX)
diff --git a/tests/llms-txt.test.ts-snapshots/reference-remix-chromium-linux.md b/tests/llms-txt.test.ts-snapshots/reference-remix-chromium-linux.md
index 6eb1e556..8787e675 100644
--- a/tests/llms-txt.test.ts-snapshots/reference-remix-chromium-linux.md
+++ b/tests/llms-txt.test.ts-snapshots/reference-remix-chromium-linux.md
@@ -62,7 +62,8 @@ The required fields are:
The optional fields are:
* `characteristics` (`string[]`) - A list of [characteristics](/fingerprints#built-in-characteristics) to be used to uniquely identify clients.
-* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See [Load balancers & proxies](#load-balancers--proxies) below for an example.
+* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+* `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you trust (such as `x-fah-client-ip`). This value is _preferred_ over IP addresses provided by the framework and IP addresses found in other headers based on the platform, in both development and production. It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such as `x-forwarded-for`). It can contain IPv4 or IPv6 addresses. Proxies are filtered out. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
* [TS](#tab-panel-XXX)
* [JS](#tab-panel-XXX)
@@ -171,32 +172,7 @@ index.js
[Section titled “Load balancers & proxies”](#load-balancers--proxies)
-If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the real client IP address plus a list of proxies that the request has passed through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the client, so you should only trust it if you are sure that the load balancer is setting it correctly. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header by setting the `proxies` field in the configuration. This should be a list of the IP addresses or the CIDR range of your load balancers to be removed, so that the last IP address in the list is the real client IP address.
-
-#### Example
-
-[Section titled “Example”](#example)
-
-For example, if the load balancer is at `100.100.100.100` and the client IP address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use `192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-```
-1import arcjet from "@arcjet/remix";2
-3const aj = arcjet({4 key: process.env.ARCJET_KEY!,5 rules: [],6 proxies: [7 "100.100.100.100", // A single IP8 "100.100.100.0/24", // A CIDR for the range9 ],10});
-```
+If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address. You can configure Arcjet to trust particular IP addresses. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
Protect
-------
@@ -435,7 +411,7 @@ The following are available on all pricing plans:
#### Example
-[Section titled “Example”](#example-1)
+[Section titled “Example”](#example)
* [TS](#tab-panel-XXX)
* [JS](#tab-panel-XXX)
diff --git a/tests/llms-txt.test.ts-snapshots/reference-sveltekit-chromium-linux.md b/tests/llms-txt.test.ts-snapshots/reference-sveltekit-chromium-linux.md
index 947d47b6..0f37f529 100644
--- a/tests/llms-txt.test.ts-snapshots/reference-sveltekit-chromium-linux.md
+++ b/tests/llms-txt.test.ts-snapshots/reference-sveltekit-chromium-linux.md
@@ -80,7 +80,8 @@ The required fields are:
The optional fields are:
* `characteristics` (`string[]`) - A list of [characteristics](/fingerprints#built-in-characteristics) to be used to uniquely identify clients.
-* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See [Load balancers & proxies](#load-balancers--proxies) below for an example.
+* `proxies` (`string[]`) - A list of one or more trusted proxies. These addresses will be excluded when Arcjet is determining the client IP address. This is useful if you are behind a load balancer or proxy that sets the client IP address in a header. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
+* `trustedIpHeader` (`string`) - Name of (lowercase) HTTP request header that you trust (such as `x-fah-client-ip`). This value is _preferred_ over IP addresses provided by the framework and IP addresses found in other headers based on the platform, in both development and production. It can point to a regular IP (such as `x-client-ip`) or a list of IPs (such as `x-forwarded-for`). It can contain IPv4 or IPv6 addresses. Proxies are filtered out. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
* [TS](#tab-panel-XXX)
* [JS](#tab-panel-XXX)
@@ -194,32 +195,7 @@ index.js
[Section titled “Load balancers & proxies”](#load-balancers--proxies)
-If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address.
-
-To fix this, most load balancers will set the `X-Forwarded-For` header with the real client IP address plus a list of proxies that the request has passed through.
-
-The problem with is that the `X-Forwarded-For` header can be spoofed by the client, so you should only trust it if you are sure that the load balancer is setting it correctly. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) for more details.
-
-You can configure Arcjet to trust IP addresses in the `X-Forwarded-For` header by setting the `proxies` field in the configuration. This should be a list of the IP addresses or the CIDR range of your load balancers to be removed, so that the last IP address in the list is the real client IP address.
-
-#### Example
-
-[Section titled “Example”](#example)
-
-For example, if the load balancer is at `100.100.100.100` and the client IP address is `192.168.1.1`, the `X-Forwarded-For` header will be:
-
-```
-X-Forwarded-For: 192.168.1.1, 100.100.100.100
-```
-
-You should set the `proxies` field to `["100.100.100.100"]` so Arcjet will use `192.168.1.1` as the client IP address.
-
-You can also specify CIDR ranges to match multiple IP addresses.
-
-```
-1import { env } from "$env/dynamic/private";2import arcjet from "@arcjet/sveltekit";3
-4const aj = arcjet({5 key: env.ARCJET_KEY!,6 rules: [],7 proxies: [8 "100.100.100.100", // A single IP9 "100.100.100.0/24", // A CIDR for the range10 ],11});
-```
+If your application is behind a load balancer, Arcjet will only see the IP address of the load balancer and not the real client IP address. You can configure Arcjet to trust particular IP addresses. See “[Concepts: Client IP](/concepts/client-ip)” for more info.
Protect
-------
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-architecture-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-architecture-dark-chromium-linux.png
index d8dad5b0..44cf850c 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-architecture-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-architecture-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-architecture-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-architecture-light-chromium-linux.png
index 8aa5e637..50f5030f 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-architecture-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-architecture-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-best-practices-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-best-practices-dark-chromium-linux.png
index c0ab47b7..b779379e 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-best-practices-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-best-practices-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-best-practices-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-best-practices-light-chromium-linux.png
index 46e3e06e..23d54a63 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-best-practices-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-best-practices-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-comparisons-aikido-vs-arcjet-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-comparisons-aikido-vs-arcjet-dark-chromium-linux.png
index 13c8e1d1..524144c8 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-comparisons-aikido-vs-arcjet-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-comparisons-aikido-vs-arcjet-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-comparisons-aikido-vs-arcjet-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-comparisons-aikido-vs-arcjet-light-chromium-linux.png
index 0ad9df83..80374627 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-comparisons-aikido-vs-arcjet-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-comparisons-aikido-vs-arcjet-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-comparisons-vercel-botid-vs-arcjet-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-comparisons-vercel-botid-vs-arcjet-dark-chromium-linux.png
index 28c52dcb..e2c5bdd1 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-comparisons-vercel-botid-vs-arcjet-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-comparisons-vercel-botid-vs-arcjet-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-comparisons-vercel-botid-vs-arcjet-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-comparisons-vercel-botid-vs-arcjet-light-chromium-linux.png
index 48adf412..ff3954d3 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-comparisons-vercel-botid-vs-arcjet-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-comparisons-vercel-botid-vs-arcjet-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-dark-chromium-linux.png
index 6a225570..cef69b20 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-light-chromium-linux.png
index 7ab757dc..a55b31f0 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-quick-start-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-quick-start-dark-chromium-linux.png
index e1e990b7..dad388ea 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-quick-start-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-quick-start-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-quick-start-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-quick-start-light-chromium-linux.png
index 6d5d2a77..98a7ed48 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-quick-start-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-quick-start-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-reference-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-reference-dark-chromium-linux.png
index 8ca006df..df69356e 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-reference-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-reference-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-reference-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-reference-light-chromium-linux.png
index b8179ac0..5adec311 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-email-validation-reference-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-email-validation-reference-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-examples-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-examples-dark-chromium-linux.png
index f6a8092b..1ad3b7c6 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-examples-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-examples-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-examples-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-examples-light-chromium-linux.png
index 6803841d..c3fff1a4 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-examples-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-examples-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-filters-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-filters-dark-chromium-linux.png
index 2331aea8..b99ab698 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-filters-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-filters-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-filters-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-filters-light-chromium-linux.png
index f9bb0ab0..f19c133a 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-filters-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-filters-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-filters-quick-start-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-filters-quick-start-dark-chromium-linux.png
index 66123740..54661fca 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-filters-quick-start-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-filters-quick-start-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-filters-quick-start-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-filters-quick-start-light-chromium-linux.png
index a6fe63f7..395cab77 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-filters-quick-start-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-filters-quick-start-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-filters-reference-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-filters-reference-dark-chromium-linux.png
index 64b10674..6786f0b2 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-filters-reference-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-filters-reference-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-filters-reference-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-filters-reference-light-chromium-linux.png
index d8feba68..795461fd 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-filters-reference-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-filters-reference-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-fingerprints-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-fingerprints-dark-chromium-linux.png
index ce2828a5..9623f9d0 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-fingerprints-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-fingerprints-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-fingerprints-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-fingerprints-light-chromium-linux.png
index bcb2d65c..c7593b4a 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-fingerprints-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-fingerprints-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-get-started-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-get-started-dark-chromium-linux.png
index 64bd0f7d..a3078eeb 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-get-started-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-get-started-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-get-started-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-get-started-light-chromium-linux.png
index 72b24df2..b0e827ad 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-get-started-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-get-started-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-home-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-home-dark-chromium-linux.png
index c0d89129..9ad67595 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-home-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-home-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-home-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-home-light-chromium-linux.png
index 93337b84..6e657896 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-home-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-home-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-inspect-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-inspect-dark-chromium-linux.png
index 4188d902..8c0a1635 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-inspect-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-inspect-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-inspect-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-inspect-light-chromium-linux.png
index 7113c250..9eafc9f5 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-inspect-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-inspect-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-authjs-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-authjs-dark-chromium-linux.png
index c4633a66..0a102ed4 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-authjs-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-authjs-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-authjs-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-authjs-light-chromium-linux.png
index a2b01d8a..94a0cd02 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-authjs-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-authjs-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-better-auth-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-better-auth-dark-chromium-linux.png
index d6571805..37bfa5a1 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-better-auth-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-better-auth-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-better-auth-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-better-auth-light-chromium-linux.png
index da702fb2..e2691422 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-better-auth-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-better-auth-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-clerk-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-clerk-dark-chromium-linux.png
index 6eae57c0..e56a01c5 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-clerk-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-clerk-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-clerk-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-clerk-light-chromium-linux.png
index f94dd796..e412dbe6 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-clerk-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-clerk-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-langchain-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-langchain-dark-chromium-linux.png
index 3a9b8f3d..25c75574 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-langchain-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-langchain-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-langchain-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-langchain-light-chromium-linux.png
index 1ec16899..bb542160 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-langchain-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-langchain-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-nextauth-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-nextauth-dark-chromium-linux.png
index 31be7859..e6b2be01 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-nextauth-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-nextauth-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-nextauth-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-nextauth-light-chromium-linux.png
index f450a946..a8b160ba 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-nextauth-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-nextauth-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-openai-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-openai-dark-chromium-linux.png
index 9a924384..83f93da5 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-openai-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-openai-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-integrations-openai-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-integrations-openai-light-chromium-linux.png
index 358dc2f6..36d9a247 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-integrations-openai-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-integrations-openai-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-ip-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-ip-dark-chromium-linux.png
index 78184916..3930b1ec 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-ip-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-ip-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-ip-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-ip-light-chromium-linux.png
index b11ff62b..fd14853d 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-ip-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-ip-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-limitations-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-limitations-dark-chromium-linux.png
index b5ba9d9c..0796adc1 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-limitations-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-limitations-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-limitations-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-limitations-light-chromium-linux.png
index 681cdf15..bbf83ef7 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-limitations-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-limitations-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-nosecone-quick-start-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-nosecone-quick-start-dark-chromium-linux.png
index 4f65fddf..3f73f524 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-nosecone-quick-start-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-nosecone-quick-start-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-nosecone-quick-start-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-nosecone-quick-start-light-chromium-linux.png
index a561cec7..3e15817f 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-nosecone-quick-start-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-nosecone-quick-start-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-nosecone-reference-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-nosecone-reference-dark-chromium-linux.png
index 41a62acc..996a2219 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-nosecone-reference-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-nosecone-reference-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-nosecone-reference-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-nosecone-reference-light-chromium-linux.png
index 88ab93dd..f1c087c1 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-nosecone-reference-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-nosecone-reference-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-privacy-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-privacy-dark-chromium-linux.png
index a0362847..334b4329 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-privacy-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-privacy-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-privacy-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-privacy-light-chromium-linux.png
index ba94a456..bb5b8559 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-privacy-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-privacy-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-redact-quick-start-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-redact-quick-start-dark-chromium-linux.png
index 9d0e48d3..70b5038f 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-redact-quick-start-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-redact-quick-start-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-redact-quick-start-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-redact-quick-start-light-chromium-linux.png
index bb973b53..975f7436 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-redact-quick-start-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-redact-quick-start-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-redact-reference-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-redact-reference-dark-chromium-linux.png
index 42010c7c..d68c87e9 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-redact-reference-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-redact-reference-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-redact-reference-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-redact-reference-light-chromium-linux.png
index 3a731013..b08dd937 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-redact-reference-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-redact-reference-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-astro-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-astro-dark-chromium-linux.png
index 4b8519b0..14592ac4 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-astro-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-astro-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-astro-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-astro-light-chromium-linux.png
index d7fbf03a..167694f2 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-astro-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-astro-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-bun-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-bun-dark-chromium-linux.png
index 72d2b5aa..ed6cffed 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-bun-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-bun-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-bun-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-bun-light-chromium-linux.png
index 834e6276..8f3e01e4 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-bun-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-bun-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-deno-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-deno-dark-chromium-linux.png
index 87da9a56..247116c4 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-deno-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-deno-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-deno-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-deno-light-chromium-linux.png
index 0fa810c8..7ab01290 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-deno-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-deno-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-fastify-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-fastify-dark-chromium-linux.png
index a05864ed..fef75cae 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-fastify-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-fastify-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-fastify-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-fastify-light-chromium-linux.png
index a96d784a..9d95b3ed 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-fastify-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-fastify-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-nestjs-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-nestjs-dark-chromium-linux.png
index bcd467e2..0bbf0d3e 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-nestjs-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-nestjs-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-nestjs-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-nestjs-light-chromium-linux.png
index 64a1032e..5ab24966 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-nestjs-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-nestjs-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-nextjs-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-nextjs-dark-chromium-linux.png
index 9cffafd5..040d9ec2 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-nextjs-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-nextjs-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-nextjs-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-nextjs-light-chromium-linux.png
index 2da8ef86..65d99ed6 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-nextjs-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-nextjs-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-nodejs-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-nodejs-dark-chromium-linux.png
index bb7091ab..1bcfa3b2 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-nodejs-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-nodejs-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-nodejs-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-nodejs-light-chromium-linux.png
index 579641c9..9b6b71fc 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-nodejs-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-nodejs-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-nuxt-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-nuxt-dark-chromium-linux.png
index 8f4660f0..fb6a0b3b 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-nuxt-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-nuxt-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-nuxt-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-nuxt-light-chromium-linux.png
index 38e0f9df..41f6fdf0 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-nuxt-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-nuxt-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-react-router-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-react-router-dark-chromium-linux.png
index 00a9f1c2..541342c0 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-react-router-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-react-router-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-react-router-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-react-router-light-chromium-linux.png
index 1dd0fcfa..a7f5abcb 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-react-router-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-react-router-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-remix-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-remix-dark-chromium-linux.png
index 317f2569..d5f94a27 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-remix-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-remix-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-remix-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-remix-light-chromium-linux.png
index f9b03ba0..76a16724 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-remix-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-remix-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-sveltekit-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-sveltekit-dark-chromium-linux.png
index 96778612..12c1ec97 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-sveltekit-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-sveltekit-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-reference-sveltekit-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-reference-sveltekit-light-chromium-linux.png
index a8932699..13c89337 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-reference-sveltekit-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-reference-sveltekit-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-regions-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-regions-dark-chromium-linux.png
index fba01ea0..8e9328ed 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-regions-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-regions-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-regions-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-regions-light-chromium-linux.png
index 6fe09e5e..9c7e7e6a 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-regions-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-regions-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-security-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-security-dark-chromium-linux.png
index fa5b7d63..70feb621 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-security-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-security-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-security-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-security-light-chromium-linux.png
index c26695bc..677ba6ab 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-security-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-security-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-dark-chromium-linux.png
index be5ab224..92f29fe3 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-light-chromium-linux.png
index 1be84dd1..faf76cbd 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-quick-start-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-quick-start-dark-chromium-linux.png
index b72921b0..09f0ee8e 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-quick-start-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-quick-start-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-quick-start-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-quick-start-light-chromium-linux.png
index 0315b0fe..6b5cd67c 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-quick-start-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-quick-start-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-reference-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-reference-dark-chromium-linux.png
index 5a3652f3..a72aaf21 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-reference-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-reference-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-reference-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-reference-light-chromium-linux.png
index 1bd332b2..1ba329f7 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-reference-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-sensitive-info-reference-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-shield-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-shield-dark-chromium-linux.png
index e7c5eda2..2115eec0 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-shield-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-shield-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-shield-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-shield-light-chromium-linux.png
index 1908de32..9a0f66f1 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-shield-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-shield-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-shield-quick-start-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-shield-quick-start-dark-chromium-linux.png
index cfe64a76..9f09da4b 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-shield-quick-start-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-shield-quick-start-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-shield-quick-start-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-shield-quick-start-light-chromium-linux.png
index 7ff0fd51..cc82cc37 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-shield-quick-start-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-shield-quick-start-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-shield-reference-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-shield-reference-dark-chromium-linux.png
index fd77047c..c9037322 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-shield-reference-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-shield-reference-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-shield-reference-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-shield-reference-light-chromium-linux.png
index 276e5d6b..85382b87 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-shield-reference-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-shield-reference-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-dark-chromium-linux.png
index 1345e335..3f8e528d 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-light-chromium-linux.png
index 8c72892b..6f1eba29 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-quick-start-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-quick-start-dark-chromium-linux.png
index 8958bd0b..7a6e3912 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-quick-start-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-quick-start-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-quick-start-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-quick-start-light-chromium-linux.png
index 90459f49..bbc97440 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-quick-start-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-quick-start-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-reference-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-reference-dark-chromium-linux.png
index 648ed11f..3443c214 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-reference-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-reference-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-reference-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-reference-light-chromium-linux.png
index 12aa8953..12f3d60b 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-reference-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-signup-protection-reference-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-support-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-support-dark-chromium-linux.png
index a71b5235..e929ce11 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-support-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-support-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-support-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-support-light-chromium-linux.png
index 0c25cee4..ecc0741b 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-support-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-support-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-testing-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-testing-dark-chromium-linux.png
index 0efaad1b..f789169c 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-testing-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-testing-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-testing-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-testing-light-chromium-linux.png
index e2c1987f..10ca0c3e 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-testing-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-testing-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-troubleshooting-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-troubleshooting-dark-chromium-linux.png
index 8bbe56a6..fd3e4c59 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-troubleshooting-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-troubleshooting-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-troubleshooting-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-troubleshooting-light-chromium-linux.png
index 00da00dd..07fd326e 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-troubleshooting-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-troubleshooting-light-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-upgrading-sdk-migration-dark-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-upgrading-sdk-migration-dark-chromium-linux.png
index d9cc307d..cacd0636 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-upgrading-sdk-migration-dark-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-upgrading-sdk-migration-dark-chromium-linux.png differ
diff --git a/tests/screenshot.test.ts-snapshots/screenshot-upgrading-sdk-migration-light-chromium-linux.png b/tests/screenshot.test.ts-snapshots/screenshot-upgrading-sdk-migration-light-chromium-linux.png
index 57a3694f..18e5e067 100644
Binary files a/tests/screenshot.test.ts-snapshots/screenshot-upgrading-sdk-migration-light-chromium-linux.png and b/tests/screenshot.test.ts-snapshots/screenshot-upgrading-sdk-migration-light-chromium-linux.png differ