The Challenge
Notion is arguably the most powerful workspace and database engine for modern teams. However, it severely lacks native, customizable charting and data visualization options.
To visualize Notion databases, users typically resort to heavy third-party SaaS tools that inject clunky iframes, require complex bidirectional data synchronization, and often break the clean aesthetics of a Notion workspace (especially when switching between Light and Dark modes).
The Solution
We built Graphify Charts, a fast Python/FastAPI rendering engine that bypasses traditional heavy iframes entirely. Instead of syncing data to a separate database, Graphify dynamically aggregates Notion databases on-the-fly and streams beautifully rendered, native SVG charts directly into Notion embed blocks.
Architectural Approach
- Dynamic Aggregation: Securely querying Notion API databases in real-time to extract schemas, group properties, and calculate mathematical aggregates (sums, counts, averages) without ever storing the user's raw data.
- Raw SVG Streaming: Utilizing a custom Python charting module (
app.charts) to programmatically construct perfectly responsive XML/SVG nodes. The API returns animage/svg+xmlresponse, which Notion natively caches and renders instantly. - Theme Awareness: The rendering engine automatically detects query parameters to inject CSS variables, seamlessly matching Notion's native Light and Dark modes.
- Monetization Engine: Fully integrated Stripe middleware to gate premium chart limits via rate-limiting (
slowapi).
Example: The SVG Rendering Pipeline
Below is a conceptual look at how our FastAPI endpoint bypasses HTML and streams raw vector graphics directly to the client:
@app.get("/embed/{chart_id}.svg")
async def stream_notion_chart(
chart_id: str,
theme: str = "dark",
db: Session = Depends(get_db)
):
chart_config = crud.get_chart(db, chart_id)
# 1. Fetch live data from Notion API
raw_pages = notion.query_database_pages(chart_config.notion_db_id)
# 2. Aggregate the data based on user configuration
aggregated_data = notion.aggregate_data(raw_pages, chart_config.axes)
# 3. Generate raw SVG XML
svg_content = charts.render_chart(
data=aggregated_data,
type=chart_config.chart_type,
theme=theme
)
# 4. Stream directly as an image bypassing iframes
return Response(content=svg_content, media_type="image/svg+xml")
The Impact
By streaming raw SVGs rather than loading entire React applications inside iframes, charts render near-instantly instead of after the multi-second load of a heavy embed. The result is a native-feeling charting experience that lets Notion power-users build real-time dashboards without sacrificing performance or aesthetics.
Graphify is an internal tool rather than a core data engagement, but it reflects the same discipline we bring to everything: take a data source others render clunky and slow, and ship a fast, well-engineered product on top of it — pipeline, rendering, and billing included.