dom-density-map
Text-based DOM density maps for LLM browser automation — 79% fewer tokens than screenshots.
Connects to any Chrome instance via CDP (Chrome DevTools Protocol), walks the visible DOM, and renders a character grid showing element density and type. Interactive elements are indexed with labels and pixel coordinates. Designed for LLM agents that need to understand page layout without burning tokens on base64 screenshots.
Quick Start
# Run without installing
uvx dom-density-map https://example.com
# Or install
pip install dom-density-map
dom-density-map https://example.com
Prerequisite: Chrome must be running with remote debugging enabled:
google-chrome --remote-debugging-port=9222
# or on macOS:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222
Usage
# Map the current page
dom-density-map
# Navigate to a URL and map it
dom-density-map https://example.com
# Sparse mode — RLE-compressed, ~420 tokens for a complex page
dom-density-map --sparse --cols 60
# Unicode block art mode
dom-density-map --blocks --cols 80
# Reverse lookup — full DOM stack at a pixel coordinate
dom-density-map --at 694,584
# Reverse lookup — by grid coordinate (prefix 'g')
dom-density-map --at g48,40 --cols 60
# Custom CDP port (default: 9222)
dom-density-map --port 9515 https://example.com
# Works with python -m too
python -m dom_density_map --sparse --cols 60
Output Modes
Default Mode
Full character grid with column rulers. Each cell represents a pixel region:
=== DOM Density Map ===
Page: Example Domain
Viewport: 1920x1080 Grid: 80x45 (24px/cell)
Elements: 42 visible, 5 interactive
Legend: (space)=empty .=1elem :=2-3 #=4-7 @=8+
B=button L=link F=input I=image/video T=text
0 1 2 3
0123456789012345678901234567890123456789
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
::::::::::::::::::::::::::::::::::::::::
TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
--- Interactive (5) ---
L1: "More information..." at grid(40,22) px(980,540)
Sparse Mode (--sparse)
RLE-compressed with row deduplication — minimal tokens for LLM consumption:
=== DOM Density Map (sparse) ===
Page: Example Domain
Viewport: 1920x1080 Grid: 60x34 (32px/cell)
Elements: 42 visible, 5 interactive
Key: _=empty .=1 :=2-3 #=4-7 @=8+ B=btn L=link F=input I=img T=text
RLE: X5 = XXXXX
r0: L60
r1-r3: :60 (x3)
r4-r8: T60 (x5)
r9-r33: (empty)
--- Interactive (5) ---
L1: "More information..." (980,540)
Reverse Lookup (--at)
Full DOM stack at a specific point — tag, classes, attributes, state, and styles:
=== Elements at px(694,584) ===
Stack depth: 6
[0] <button> data-e2e="like-icon"
class: btn-like active
aria-pressed: true
cursor: pointer
bg: rgb(254, 44, 85)
rect: (680,570) 28x28
[1] <div>
class: action-bar
rect: (670,520) 48x200
...
Python API
import asyncio
from dom_density_map import CDP, get_ws_url, render_sparse_map
async def main():
ws_url = get_ws_url(port=9222)
cdp = CDP(ws_url)
await cdp.connect()
# Navigate
await cdp.navigate("https://example.com", wait=3)
# Run DOM walker
result = await cdp.execute_js("""
// ... DOM_WALKER_JS is available as dom_density_map.core.DOM_WALKER_JS
""")
data = result.get("result", {}).get("value")
# Render
output = render_sparse_map(data, max_cols=60)
print(output)
await cdp.close()
asyncio.run(main())
Or use the JS constants directly:
from dom_density_map.core import DOM_WALKER_JS, ELEMENTS_AT_JS
Token Comparison
| Method | Tokens | Info |
|---|---|---|
| Screenshot (base64 PNG) | ~2,300 | Visual only, no selectors |
dom-density-map (default) |
~1,200 | Layout + all interactive elements |
dom-density-map --sparse |
~420 | RLE-compressed, same info |
dom-density-map --at X,Y |
~550 | Full DOM stack at a point |
Element Types
| Char | Block | Meaning |
|---|---|---|
B |
\u25a3 |
Button (<button>, role="button", submit/reset inputs) |
F |
\u25a4 |
Form input (<input>, <textarea>, <select>, contenteditable) |
L |
\u25a8 |
Link (<a href="...">) |
I |
\u25a7 |
Image/media (<img>, <video>, <canvas>, <svg>) |
T |
\u25a5 |
Text block (element with >20 chars of direct text) |
. |
\u2591 |
1 element |
: |
\u2592 |
2-3 elements |
# |
\u2593 |
4-7 elements |
@ |
\u2588 |
8+ elements |
License
MIT
Metadata
Release files for dom-density-map 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| dom_density_map-0.1.0.tar.gz | 16.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dom_density_map-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.0 kB
Release files / dom_density_map-0.1.0.tar.gz
| Download URL | dom_density_map-0.1.0.tar.gz |
|---|---|
| Size | 16.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
91ff476ca00e71e97f51977c333f9efc01a4423555987a13ed0fe3b138bce014
|
|
BLAKE2b-256 checksum How to use checksums |
81c9447cb7c7a3e3cb823aeb26c1a12a5b561d18973e369aa0151bae10602660
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / dom_density_map-0.1.0-py3-none-any.whl
| Download URL | dom_density_map-0.1.0-py3-none-any.whl |
|---|---|
| Size | 12.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
981a3df84cfcbe8b3b80c8f6137a746b7d26fbd76f0c3c12838b0ce0fd5d67e6
|
|
BLAKE2b-256 checksum How to use checksums |
d0f4b1102edda604eb66e7c406a5e9b4b94bb4a44b44848beb4ef3fc82aab5f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for dom-density-map 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.