Open
Description
Goal
Enable individual components (like a chart, table, or text block) or entire Preswald applications to be rendered inside an iframe β so that Preswald apps can be embedded inside other websites, dashboards, or internal portals.
π Motivation
Preswald is great for building interactive dashboards and data apps β but sometimes users want to embed a portion of that functionality inside another product, portal, or web app. For example:
- Embedding a live Plotly chart inside a documentation site
- Sharing a single
table()
ortext()
component in a blog - Hosting a full Preswald app as a widget in a CMS or web portal
- Surfacing Preswald apps inside enterprise tools (Jira, Notion, Slack apps)
This makes Preswald more modular, composable, and shareable.
β Acceptance Criteria
- Allow running Preswald apps in a sandboxed iframe environment
- Add
--embed
flag topreswald run
orpreswald export
- Add
embed = true
option topreswald.toml
or per-component setting - Allow embedding:
- Full app at
/
- Specific component by ID via
/embed/<component_id>
- Full app at
- Serve a minimal shell layout with only the component and required JS/CSS
- Add CORS and iframe headers for embedding:
X-Frame-Options: ALLOWALL
Content-Security-Policy
withframe-ancestors
- Provide copyable embed snippets in dev server logs or docs:
<iframe src="https://myapp.preswald.dev/embed/chart-abc123" width="600" height="400" />
π Implementation Plan
1. Component Embedding Route
- Add
/embed/<component_id>
endpoint to backend - Strip layout/chrome and render only that one component
- Optionally support multiple component IDs or sections
2. Full App Embedding Mode
- When
embed = true
, load a reduced shell layout:- No side nav, branding, or toolbars
- Fit nicely into iframe with auto-sizing support
3. Developer Tools
- Log or print iframe snippet at boot time:
βΉοΈ Embed this chart in your blog: <iframe src="http://localhost:8501/embed/chart-xyz123" width="600" height="400" />
π§ͺ Testing Plan
- Build a simple app with:
plotly(fig, id="main_chart") table(df, id="my_table")
- Run:
preswald run --embed
- Open:
http://localhost:8501/embed/main_chart
http://localhost:8501/embed/my_table
- Validate:
- Renders correctly inside iframe
- CSS is scoped and responsive
- CORS and X-Frame headers are correct
π Docs To Add
-
docs/deployment/embedding.mdx
- Add example of using
<iframe>
in Notion, Hugo, Docusaurus - Mention CORS/security considerations
π§© Related Files
preswald/server_service.py
β route:/embed/<component>
frontend/src/pages/EmbedView.jsx
(new)preswald.toml
:[deployment] embeddable = true