Skip to main content

Text-based DOM density maps for LLM browser automation — 79% fewer tokens than screenshots

Project description

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

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

dom_density_map-0.1.0.tar.gz (16.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dom_density_map-0.1.0-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file dom_density_map-0.1.0.tar.gz.

File metadata

  • Download URL: dom_density_map-0.1.0.tar.gz
  • Upload date:
  • Size: 16.9 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for dom_density_map-0.1.0.tar.gz
Algorithm Hash digest
SHA256 91ff476ca00e71e97f51977c333f9efc01a4423555987a13ed0fe3b138bce014
MD5 e947f9ba5d4adcec39f3525bd8650b1d
BLAKE2b-256 81c9447cb7c7a3e3cb823aeb26c1a12a5b561d18973e369aa0151bae10602660

See more details on using hashes here.

File details

Details for the file dom_density_map-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: dom_density_map-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.1 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for dom_density_map-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 981a3df84cfcbe8b3b80c8f6137a746b7d26fbd76f0c3c12838b0ce0fd5d67e6
MD5 5f86660003ae67e7d3aef6cc0b76b7d6
BLAKE2b-256 d0f4b1102edda604eb66e7c406a5e9b4b94bb4a44b44848beb4ef3fc82aab5f3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page