Skip to main content

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)

Source distribution for dom-density-map 0.1.0
File Size Uploaded Provenance
dom_density_map-0.1.0.tar.gz 16.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for dom-density-map 0.1.0
File Interpreter ABI Platform
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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page