User Agent integration for ASGI applications.
Project description
asgi-user-agents
User Agents integration for ASGI applications. Works with Starlette, FastAPI, Quart, Litestar, Django -- or any other web framework supporting ASGI that exposes the ASGI scope.
Table of Contents
Installation
NOTE: This is alpha software. Please be sure to pin your dependencies.
Latest Release
pip install asgi-user-agents
Development Version
pip install git+https://github.com/hasansezertasan/asgi-user-agents.git
How does it work?
It simply adds a ua attribute to the request scope. This attribute is an instance of the UADetails class which abstracts the UserAgent class from the user-agents package 📄.
Usage
It's pretty simple. Just add the middleware to your ASGI application and access the ua attribute from the request scope.
from asgi_user_agents import UAMiddleware
from asgi_user_agents import UARequest as Request
from fastapi.applications import FastAPI
from starlette.middleware import Middleware
from starlette.responses import JSONResponse, Response
app = FastAPI(middleware=[Middleware(UAMiddleware)])
@app.get("/")
async def index(request: Request) -> Response:
ua = request.scope["ua"]
data = {
"ua_string": ua.ua_string,
"os": ua.os,
"os.family": ua.os.family,
"os.version": ua.os.version,
"os.version_string": ua.os.version_string,
"browser": ua.browser,
"browser.family": ua.ua.browser.family,
"browser.version": ua.ua.browser.version,
"browser.version_string": ua.ua.browser.version_string,
"device": ua.device,
"device.family": ua.device.family,
"device.brand": ua.device.brand,
"device.model": ua.device.model,
"is_provided": ua.is_provided,
"is_tablet": ua.is_tablet,
"is_mobile": ua.is_mobile,
"is_touch_capable": ua.is_touch_capable,
"is_pc": ua.is_pc,
"is_bot": ua.is_bot,
"is_email_client": ua.is_email_client,
}
return JSONResponse(data)
Framework integrations
For Litestar, FastAPI, and Django, optional contrib subpackages provide
framework-idiomatic access. The core UAMiddleware still works for any
ASGI framework — contrib is additive convenience.
Install with the relevant extra:
pip install asgi-user-agents[litestar]
pip install asgi-user-agents[fastapi]
pip install asgi-user-agents[django]
Litestar
Use UAPlugin to inject ua: UADetails and user_agent: UserAgent into route handlers. No middleware needed.
from litestar import Litestar, get
from asgi_user_agents import UADetails
from asgi_user_agents.contrib.litestar import UAPlugin
@get("/")
async def index(ua: UADetails) -> dict:
return {"is_bot": ua.is_bot, "browser": ua.browser.family}
app = Litestar(route_handlers=[index], plugins=[UAPlugin()])
If you already registered a dependency named ua or user_agent, UAPlugin will not overwrite it.
FastAPI
Use install_ua(app) plus the prebuilt UADep / UserAgentDep annotated dependencies.
from fastapi import FastAPI
from asgi_user_agents.contrib.fastapi import UADep, install_ua
app = install_ua(FastAPI())
@app.get("/")
async def index(ua: UADep) -> dict:
return {"is_bot": ua.is_bot, "browser": ua.browser.family}
install_ua is idempotent. The plain dependency functions get_ua and get_user_agent are also exported if you prefer to wire them yourself.
Django
Built on UADetails. Add the app and the middleware:
# settings.py
INSTALLED_APPS = [
# ...
"asgi_user_agents.contrib.django", # enables the template filters
]
MIDDLEWARE = [
# ...
"asgi_user_agents.contrib.django.UserAgentMiddleware",
]
The middleware attaches a lazy request.user_agent (a UADetails):
def my_view(request):
if request.user_agent.is_mobile:
...
browser = request.user_agent.browser.family
…and the same data is available as template filters:
{% load asgi_user_agents %}
{% if request|is_mobile %}Mobile{% elif request|is_pc %}Desktop{% endif %}
Resolution is scope-first: under ASGI, if the core UAMiddleware already
ran, request.user_agent reuses the parsed request.scope["ua"] with no
re-parse. Under WSGI (no scope) it falls back to parsing request.headers, so
the integration works under both deployment models. The middleware is sync- and
async-capable.
API Reference
UAMiddleware
An ASGI middleware that sets scope["ua"] to an instance of UADetails (scope refers to the ASGI scope).
app = UAMiddleware(app)
UADetails
A helper that provides shortcuts for accessing User-Agent request header.
ua = UADetails(scope)
ua: UserAgent- TheUserAgentinstance from theuser-agentspackage.ua_string: str- The user agent string.is_provided: bool-Trueif the user agent string is provided.os: OperatingSystem- The operating system details of the user agent. It's a named tuple with the following fields:family: str- The family of the operating system.version: str- The version of the operating system.version_string: str- The version of the operating system as a string.
browser: Browser- The browser details of the user agent. It's a named tuple with the following fields:family: str- The family of the browser.version: str- The version of the browser.version_string: str- The version of the browser as a string.
device: Device- The device details of the user agent. It's a named tuple with the following fields:family: str- The family of the device.brand: str- The brand of the device.model: str- The model of the device.
is_tablet: bool-Trueif the request was made by a tablet.is_mobile: bool-Trueif the request was made by a mobile device.is_touch_capable: bool-Trueif the request was made by a touch-capable device.is_pc: bool-Trueif the request was made by a PC.is_bot: bool-Trueif the request was made by a bot.is_email_client: bool-Trueif the request was made by an email client.
UARequest
For Starlette-based frameworks, use this instead of the standard starlette.requests.Request so that code editors understand that request.scope["ua"] contains an UADetails instance:
from asgi_user_agents import UARequest as Request
async def home(request: Request):
reveal_type(request.scope["ua"]) # Revealed type is 'UADetails'
Development
Clone the repository and cd into the project directory:
git clone https://github.com/hasansezertasan/asgi-user-agents
cd asgi-user-agents
Install hatch, you can follow the instructions, or simply run one of the following commands:
mise use hatch
uv tool install hatch
pipx install hatch
The commands below can also be executed using the xc task runner, which combines the usage instructions with the actual commands. Simply run xc, it will popup an interactive menu with all available tasks.
env
Initialize the environment and install the dependencies:
hatch shell
hooks
Initialize pre-commit hooks by running the following command:
pre-commit install
test
Make your changes on a new branch and run the tests:
hatch test -a
types
Make sure that the code is typed, linted, and formatted correctly:
hatch run types:all
co
Stage your changes and commit them:
Inputs: MESSAGE
git add .
git commit -m "$MESSAGE"
pr
Create a pull request and wait for the review 🤓.
gh pr new -B main
Author
- Hasan Sezer Taşan, It's me 👋.
Credits
- This project wouldn't be possible without the user-agents package 🙏.
- The project structure is inspired by the asgi-htmx 🚀 package and contains some code snippets from it 😅 (even this file).
Analysis
- Snyk Python Package Health Analysis
- Libraries.io - PyPI
- Safety DB
- PePy Download Stats
- PyPI Download Stats
- Pip Trends Download Stats
License
asgi-user-agents is distributed under the terms of the MIT license.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file asgi_user_agents-0.4.0.tar.gz.
File metadata
- Download URL: asgi_user_agents-0.4.0.tar.gz
- Upload date:
- Size: 80.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
093554979a9c8a126434c77e7465d8d28fa2ade3139add94d47e64a56cb155b4
|
|
| MD5 |
1adf5839b25c72f4f6075ee8f41a4af4
|
|
| BLAKE2b-256 |
90c7a905bb2a1cf8ed0e7b4dbd57026e05ac7a9fafa564267336ba747f2d0a30
|
File details
Details for the file asgi_user_agents-0.4.0-py3-none-any.whl.
File metadata
- Download URL: asgi_user_agents-0.4.0-py3-none-any.whl
- Upload date:
- Size: 16.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
72dc34f8bea52e417f05000534bd50dd6d35ac44bd0d61a440aef849d7211a5c
|
|
| MD5 |
618ced77255de3defdfcec102fead663
|
|
| BLAKE2b-256 |
cab28ae113d7c6f47f37c6e2fae74b762ae9694551c8578fa6384d09d87475f8
|