diff --git a/security/arcjet.html.md b/security/arcjet.html.md
index 9470f7893b..587bffbaef 100644
--- a/security/arcjet.html.md
+++ b/security/arcjet.html.md
@@ -8,13 +8,9 @@ redirect_from: /docs/reference/arcjet/
[Arcjet](https://arcjet.com) is a security layer that allows developers to protect their apps with just a few lines of code. Implement rate limiting, bot protection, email validation, and defense against common attacks.
-Arcjet is installed as a dependency in your application and doesn't require an agent or any additional infrastructure. The SDK is currently available for JS applications, with support for other languages coming soon.
+Arcjet is installed as a dependency in your application and doesn't require an agent or any additional infrastructure. The SDK is currently available for JS & Python applications, with support for other languages coming soon.
-
-
-## Get started
+## Quick start (Next.js)
A quick way to see what Arcjet can do is to deploy [the example app](https://github.com/arcjet/arcjet-example-nextjs-fly). It's also available at [example.arcjet.com](https://example.arcjet.com).
@@ -92,12 +88,7 @@ Open [http://localhost:3000](http://localhost:3000) in your browser.
## Protecting your application with Arcjet
-Once you have set your `ARCJET_KEY` secret, you can start using Arcjet to protect your application:
-
-* [Bun](https://docs.arcjet.com/get-started/bun)
-* [Next.js](https://docs.arcjet.com/get-started/nextjs)
-* [Node.js](https://docs.arcjet.com/get-started/nodejs)
-* [SvelteKit](https://docs.arcjet.com/get-started/sveltekit)
+Once you have set your `ARCJET_KEY` secret, you can start using Arcjet to protect your application. Arcjet supports many different web frameworks e.g. [Bun](https://docs.arcjet.com/get-started/bun), [Next.js](https://docs.arcjet.com/get-started/nextjs), [Node.js](https://docs.arcjet.com/get-started/nodejs), [SvelteKit](https://docs.arcjet.com/get-started/sveltekit).
### Node.js example
@@ -159,6 +150,106 @@ You can also find this example [on GitHub](https://github.com/arcjet/arcjet-js/t
Load the application and refresh the page a few times to see the rate limit in action.
+### Python + FastAPI example
+
+You can also find this example [on GitHub](https://github.com/arcjet/examples/tree/main/examples/fastapi).
+
+1. Install the Arcjet SDK:
+
+ ```cmd
+ mkdir arcjet-fastapi
+ cd arcjet-fastapi
+ uv init
+ uv add arcjet "fastapi[standard]" uvicorn
+ ```
+
+1. Create a new file at `main.py` with the contents:
+
+ ```python
+ import os
+ from fastapi import FastAPI, Request
+ from fastapi.responses import JSONResponse
+
+ from arcjet import (
+ arcjet,
+ shield,
+ detect_bot,
+ token_bucket,
+ Mode,
+ BotCategory,
+ )
+
+ app = FastAPI()
+
+ aj = arcjet(
+ key=os.environ["ARCJET_KEY"], # Get your key from https://app.arcjet.com
+ rules=[
+ # Shield protects your app from common attacks e.g. SQL injection
+ shield(mode=Mode.LIVE),
+ # Create a bot detection rule
+ detect_bot(
+ mode=Mode.LIVE,
+ allow=[
+ BotCategory.SEARCH_ENGINE, # Google, Bing, etc
+ # Uncomment to allow these other common bot categories
+ # See the full list at https://arcjet.com/bot-list
+ # BotCategory.MONITOR, # Uptime monitoring services
+ # BotCategory.PREVIEW, # Link previews e.g. Slack, Discord
+ ],
+ ),
+ # Create a token bucket rate limit. Other algorithms are supported
+ token_bucket(
+ # Tracked by IP address by default, but this can be customized
+ # See https://docs.arcjet.com/fingerprints
+ # characteristics: ["ip.src"],
+ mode=Mode.LIVE,
+ refill_rate=5, # Refill 5 tokens per interval
+ interval=10, # Refill every 10 seconds
+ capacity=10, # Bucket capacity of 10 tokens
+ ),
+ ],
+ )
+
+
+ @app.get("/")
+ async def hello(request: Request):
+ # Call protect() to evaluate the request against the rules
+ decision = await aj.protect(
+ request,
+ requested=5, # Deduct 5 tokens from the bucket
+ )
+
+ # Handle denied requests
+ if decision.is_denied():
+ status = 429 if decision.reason.is_rate_limit() else 403
+ return JSONResponse(
+ {"error": "Denied", "reason": decision.reason.to_dict()},
+ status_code=status,
+ )
+
+ # Check IP metadata (VPNs, hosting, geolocation, etc)
+ if decision.ip.is_hosting():
+ # Requests from hosting IPs are likely from bots, so they can usually be
+ # blocked. However, consider your use case - if this is an API endpoint
+ # then hosting IPs might be legitimate.
+ # https://docs.arcjet.com/blueprints/vpn-proxy-detection
+
+ return JSONResponse(
+ {"error": "Denied from hosting IP"},
+ status_code=403,
+ )
+
+ return {"message": "Hello world", "decision": decision.to_dict()}
+ ```
+
+1. Run your application with your Arcjet key in the environment:
+
+ ```cmd
+ export ARCJET_ENV=development
+ export ARCJET_KEY=ajkey_yourkey
+ uv run uvicorn main:app --reload
+ ```
+
## Pricing
See [the Arcjet pricing page](https://arcjet.com/pricing).