Connect Retool to Mural using a REST API Resource pointed at https://app.mural.co/api/public/v1/. Authenticate with a Mural OAuth 2.0 token or personal access token from the Developer Settings panel. Build post-workshop analysis dashboards that retrieve murals, extract sticky note widgets, aggregate voting results, and turn facilitation session data into structured, shareable reports.
| Fact | Value |
|---|---|
| Tool | Mural |
| Category | Productivity |
| Method | REST API Resource |
| Difficulty | Intermediate |
| Time required | 25 minutes |
| Last updated | April 2026 |
Build a Mural Workshop Analysis Dashboard in Retool
Mural is the go-to platform for digital facilitation — design thinking workshops, retrospectives, OKR planning sessions, and sprint reviews all produce rich data locked inside Mural boards. Sticky notes, voting dots, sticky clusters, and drawing annotations represent decisions, priorities, and insights. But exporting that data for downstream analysis, reporting to leadership, or feeding into project management tools is cumbersome from Mural's native interface. A Retool app connected to Mural's API unlocks that data systematically.
With the Mural API, your Retool application can list all murals within a workspace, retrieve every widget on a board (sticky notes, text boxes, shapes, connectors, images), read widget content and metadata (position, color, author, vote count), and organize that data into structured dashboards. This means a workshop facilitator can capture a brainstorming session's output — hundreds of sticky notes with voting results — and immediately surface the top-voted ideas in a prioritized table, ready to share with stakeholders who never logged into Mural.
A particularly powerful pattern is combining Mural data with your project management systems. After a sprint planning session in Mural, a Retool dashboard can extract the to-do sticky notes, allow a team lead to review and approve them, then bulk-create tasks in Jira or Asana with a single click. This closes the gap between facilitation tools and execution systems, turning workshop outputs into trackable work items without manual data entry.
Integration method
Mural provides a REST API (v1) that grants programmatic access to workspaces, rooms, murals, widgets, and members. Retool connects via a REST API Resource using Bearer token authentication, with tokens obtained either through Mural's OAuth 2.0 flow or by generating a personal access token in Mural's Developer Settings. Because Retool proxies all requests server-side, Mural credentials never reach the end user's browser, eliminating CORS concerns entirely.
Prerequisites
- A Mural account with Developer access (available on Team plan and above)
- Access to Mural's Developer Settings to generate a personal access token or create an OAuth 2.0 app
- Your Mural workspace ID (found in workspace settings or the URL path)
- A Retool account with permission to create and configure Resources
- Familiarity with Retool's REST API Resource setup and JavaScript transformers
Step-by-step guide
Generate a Mural access token
Mural offers two authentication methods for API access: a personal access token (simplest for internal tools) and OAuth 2.0 (required for multi-user applications). For a Retool admin panel used by internal teams, a personal access token is the recommended approach. To generate one, log in to your Mural account and navigate to your profile icon in the top-right corner, then select Developer Settings. In the Developer Settings panel, click Personal Access Tokens, then click Create Token. Give the token a descriptive name like 'Retool Integration'. Select the required scopes: murals:read to retrieve mural lists and widget data, workspaces:read to list workspace rooms and members, and optionally murals:write if your Retool app will create or update murals. Set an expiration period (90 days is a practical default for internal tools, though you can choose longer). Click Create and copy the token immediately — it is only shown once. Store this token in Retool as a Configuration Variable (Settings → Configuration Variables) named MURAL_ACCESS_TOKEN marked as a secret. For teams needing per-user authentication, create an OAuth 2.0 application in Developer Settings instead: provide a Client ID, Client Secret, and set the Redirect URI to your Retool app's domain. OAuth tokens must be refreshed using the refresh_token grant.
Pro tip: Personal access tokens in Mural are tied to the account that created them. Create a dedicated Mural service account (a team member seat used exclusively for API integrations) so that the token does not expire if the original creator leaves the team or changes their Mural password.
Expected result: A Mural personal access token has been generated and saved as a secret Configuration Variable in Retool, ready to be used in the REST API Resource authentication.
Configure the Mural REST API Resource in Retool
With your access token ready, create the Mural REST API Resource in Retool. Navigate to Resources in the left sidebar and click Add Resource. Select REST API from the resource type list. Name the resource 'Mural API'. Set the Base URL to https://app.mural.co/api/public/v1. Under Authentication, select Bearer Token and enter {{ retoolContext.configVars.MURAL_ACCESS_TOKEN }} — this references the Configuration Variable you created, ensuring the token is never exposed in the resource configuration UI. Under Default Headers, add Content-Type: application/json and Accept: application/json. Mural's API follows standard REST conventions with JSON responses. Leave the resource as shared (all Retool users use the same service account token) — this is appropriate for internal ops dashboards. Click Save and use the Test Connection option to verify connectivity. A successful test returns a 200 response. If you see 401, the token may have expired or the Configuration Variable name may be mistyped. If you see 403, the token scopes may be insufficient — return to Mural Developer Settings and verify the selected scopes include murals:read.
Pro tip: Mural's API rate limit is 100 requests per minute per token. For dashboards that load multiple queries simultaneously (mural list + widget data + member list), stagger query triggers using event handlers rather than auto-running all queries on app load, to avoid hitting rate limits during peak usage.
Expected result: The Mural API Resource is saved in Retool and a test connection confirms a successful 200 response, indicating the Bearer token and base URL are correctly configured.
Build queries to list murals and retrieve widget data
With the Resource configured, create the core data-fetching queries. First, create a query named 'getWorkspaceMurals'. Set Method to GET and Path to /workspaces/{{ workspaceIdInput.value }}/murals. Add URL parameters: limit → 50, next → {{ getWorkspaceMurals.data?.next || '' }} for cursor-based pagination. The response returns a value array of mural objects with fields including id, title, createdOn, updatedOn, status, and visitorCount. Create a JavaScript transformer to normalize the response: extract the value array, format timestamps using toLocaleDateString(), and add a computed 'stale' boolean flag (true when the updatedOn date is older than 90 days). Next, create a query named 'getMuralWidgets'. Set Method to GET and Path to /murals/{{ muralsTable.selectedRow.id }}/widgets. This endpoint returns all widgets on the selected mural — sticky notes, text boxes, shapes, images, and connectors. Add URL parameters: limit → 200. In a transformer, filter to only sticky note widgets (where type === 'sticky note' or type === 'sticky'), extract the content text, color hex code, x/y position, and the votes array (each vote has a userId). Compute a voteCount from the votes array length. Return a sorted array with the highest-voted sticky notes at the top. These two queries drive the main dashboard Table components.
1// Transformer: normalize Mural widget data for the Table2const widgets = data?.value || [];3const stickyTypes = ['sticky note', 'sticky', 'stickynote'];45return widgets6 .filter(w => stickyTypes.includes((w.type || '').toLowerCase()))7 .map(w => ({8 id: w.id,9 content: w.htmlContent10 ? w.htmlContent.replace(/<[^>]+>/g, '').trim()11 : (w.text || w.title || '(empty)'),12 color: w.style?.backgroundColor || w.backgroundColor || '#FFEB3B',13 author: w.createdBy?.name || w.createdBy?.email || 'Unknown',14 vote_count: Array.isArray(w.votes) ? w.votes.length : 0,15 x: Math.round(w.x || 0),16 y: Math.round(w.y || 0),17 created_at: w.createdOn18 ? new Date(w.createdOn).toLocaleDateString()19 : 'N/A'20 }))21 .sort((a, b) => b.vote_count - a.vote_count);Pro tip: Mural widget content may be stored as htmlContent (HTML-formatted) or plain text depending on widget type. The transformer above strips HTML tags with a regex. For long sticky note content, add a truncation in the Table's column formatter to keep the Table readable, and show full content in a detail panel when a row is selected.
Expected result: The getWorkspaceMurals query returns a paginated list of murals in the workspace, and getMuralWidgets returns normalized sticky note data sorted by vote count for the selected mural.
Build the workshop analysis dashboard UI
With working queries, assemble the analysis dashboard. Start with a Text Input named 'workspaceIdInput' at the top of the canvas for entering the Mural workspace ID, pre-populated with your team's workspace ID. Below it, add a Table component named 'muralsTable' with Data set to {{ getWorkspaceMurals.data }}. Configure columns: title, updatedOn (formatted as date), visitorCount, and a 'Stale?' column using the computed boolean from the transformer (display as a Tag: green 'Active' vs red 'Stale'). Enable row selection on the Table so that clicking a mural triggers the getMuralWidgets query automatically via an event handler (on row select → trigger getMuralWidgets). In the right column, add a second Table named 'widgetsTable' with Data set to {{ getMuralWidgets.data }}. Configure columns: content (wide), color (display as a colored square Tag), vote_count (sortable, default descending), author, and created_at. Above the widgets table, add a Chart component (Bar type) with X-axis set to {{ getMuralWidgets.data.map(w => w.content.slice(0, 30)) }} and Y-axis set to {{ getMuralWidgets.data.map(w => w.vote_count) }} to visualize the voting distribution. Add a stat card row above the chart showing: Total Stickies ({{ getMuralWidgets.data.length }}), Total Votes Cast ({{ getMuralWidgets.data.reduce((sum, w) => sum + w.vote_count, 0) }}), and Unique Authors ({{ new Set(getMuralWidgets.data.map(w => w.author)).size }}). Add a Download CSV button that exports the widget table data using Retool's built-in table export feature.
Pro tip: For complex integrations involving multi-mural analysis, cross-session theme tracking, and automated reporting workflows that push Mural insights to project management tools, RapidDev's team can help architect and build your Retool workshop analytics solution.
Expected result: A complete workshop analysis dashboard displays a list of murals, shows sticky notes sorted by vote count when a mural is selected, visualizes voting distribution in a bar chart, and provides summary stat cards for the session.
Add voting analysis and theme grouping
To make the dashboard actionable for facilitators, add theme grouping and export capabilities. Create a JavaScript query named 'groupByColor' that runs client-side (no resource needed) to group widgets by their background color — which typically represents themes in workshop templates. In the query body, reference getMuralWidgets.data and use Array.reduce() to bucket stickies by their color hex code, computing a count and total votes per color group. Display the color group summary in a small Table or Stat grid above the main widget table, showing: color swatch, count of stickies, and total votes — so facilitators can quickly see which theme generated the most ideas and which got the most votes. Add a Select component that lets users filter widgetsTable by color, using a Table filter with {{ colorFilter.value ? getMuralWidgets.data.filter(w => w.color === colorFilter.value) : getMuralWidgets.data }} as the data source. Finally, add a Form section for documenting session outcomes: a Text Area for 'Key Decisions', a Text Area for 'Next Steps', and a Button that triggers a query to INSERT a workshop_summary row into a connected PostgreSQL table with the mural ID, widget counts, key decisions, next steps, and timestamp. This turns the Retool dashboard into a complete workshop documentation tool.
1// JavaScript query: group sticky notes by color for theme analysis2const widgets = getMuralWidgets.data || [];34const colorGroups = widgets.reduce((acc, widget) => {5 const color = widget.color || '#FFEB3B';6 if (!acc[color]) {7 acc[color] = { color, count: 0, total_votes: 0, stickies: [] };8 }9 acc[color].count += 1;10 acc[color].total_votes += widget.vote_count;11 acc[color].stickies.push(widget.content);12 return acc;13}, {});1415return Object.values(colorGroups)16 .sort((a, b) => b.total_votes - a.total_votes)17 .map(group => ({18 color: group.color,19 sticky_count: group.count,20 total_votes: group.total_votes,21 avg_votes: (group.total_votes / group.count).toFixed(1)22 }));Pro tip: Mural color values in the API response may be hex codes, named colors, or Mural's internal color identifiers depending on the widget version. Add a color label mapping in your transformer (e.g., '#FFC0CB' → 'Pink / User Needs', '#90EE90' → 'Green / Solutions') to make the theme grouping more readable for non-technical stakeholders.
Expected result: The dashboard shows sticky notes grouped by color with total vote counts per theme, a color filter on the main table, and a session documentation form that saves workshop outcomes to a database.
Common use cases
Build a post-workshop sticky note aggregator
Create a Retool dashboard that retrieves all widgets from a selected Mural board, filters to sticky notes, and displays them in a Table sorted by vote count. Allow the facilitator to group sticky notes by color (which typically represents themes), add notes or categories, and export the aggregated results to a CSV or push to a database for long-term storage.
Build a Retool workshop analysis panel for Mural. A dropdown selects a mural board by name. A query fetches all widgets, filters to stickies, and displays them in a Table sorted by vote count descending. Include columns for content, color, author, and vote count. Add a 'Export to CSV' button.
Copy this prompt to try it in Retool
Build a voting results and prioritization dashboard
Create a Retool prioritization panel that reads sticky notes from a Mural ideation session, displays a bar chart of vote distribution across ideas, and surfaces the top 10 voted items in a ranking table. Allow team leads to mark items as 'Selected', 'Parked', or 'Rejected' with status saved to a Retool Database or PostgreSQL instance for meeting documentation.
Build a Retool voting results dashboard for Mural. Fetch all sticky notes with vote counts from a specified mural, display a Bar Chart of top 20 ideas by votes, and show a Table below with content, votes, and a Status dropdown. Include a Save button that writes the status decisions to a connected PostgreSQL table.
Copy this prompt to try it in Retool
Build a workspace inventory and mural management panel
Create a Retool admin panel that lists all murals across workspace rooms, showing creator, creation date, last modified date, and member count. Allow administrators to view mural details, identify stale boards not accessed in 90+ days, and manage workspace hygiene by tracking which teams are actively using Mural versus which boards are dormant.
Build a Retool Mural workspace manager. List all murals across all rooms in a Table with columns for name, room, creator, creation date, and last modified date. Add a filter for 'Stale (not modified in 90 days)'. Show a Summary stat card for total murals, active rooms, and team member count.
Copy this prompt to try it in Retool
Troubleshooting
401 Unauthorized when querying Mural API — 'Invalid token' or 'Expired token'
Cause: Personal access tokens in Mural have a configurable expiration date. Once expired, all API calls return 401 until a new token is generated and the Retool Configuration Variable is updated. Tokens can also be invalidated manually from Developer Settings.
Solution: Log in to Mural and navigate to Developer Settings → Personal Access Tokens. Check if the token is listed as expired. If so, create a new token with the same scopes, update the MURAL_ACCESS_TOKEN Configuration Variable in Retool's Settings panel, and re-test the resource connection. Consider setting a calendar reminder 1 week before the token's expiration date to proactively rotate it.
Empty widget list returned — the getMuralWidgets query returns zero results even for boards known to have sticky notes
Cause: Mural's API widget endpoint may return an empty value array if the mural has no widgets of any type (including connectors and shapes), or if the mural ID passed in the path is incorrect. Also, some older mural boards may use a different API version endpoint.
Solution: Verify the mural ID by logging into Mural, opening the board, and checking the URL — the mural ID appears as a numeric segment in the path (e.g., /app/mural/team/room/123456789). Confirm the mural ID in the widgetsTable selected row matches this value. Also check that the muralsTable.selectedRow.id is bound correctly in the query path and is not undefined. Try the query with a hard-coded mural ID first to confirm the endpoint is working.
403 Forbidden when listing murals — 'Access denied to workspace'
Cause: The personal access token was generated by a Mural account that does not have access to the workspace being queried, or the token's scope does not include workspaces:read. Mural access control is workspace-scoped — a token from a guest account may not see all rooms.
Solution: Ensure the Mural account used to generate the token is a full member (not a guest) of the workspace and has at least Viewer access to the rooms containing the murals you want to query. In Mural Developer Settings, verify the token includes both workspaces:read and murals:read scopes. If using OAuth 2.0, confirm the user who authenticated the OAuth app is a workspace member.
Sticky note content appears as raw HTML tags — content field shows '<p>Idea text</p>' instead of 'Idea text'
Cause: Mural stores widget text content as HTML in the htmlContent field for rich-text sticky notes. When displayed directly in a Retool Table, the HTML tags appear as literal text rather than rendered formatting.
Solution: Apply an HTML-stripping transformer on the widget data before displaying it in the Table. Use a replace() with a regex that removes all HTML tags, leaving only the plain text. The transformer code in Step 3 handles this — ensure the transformer is active and that you are referencing getMuralWidgets.data (which has the transformer applied) rather than getMuralWidgets.rawData (which contains the unprocessed API response).
1// Strip HTML from Mural widget content2const stripHtml = (html) => {3 if (!html) return '';4 return html.replace(/<[^>]+>/g, '').replace(/ /g, ' ').trim();5};6// Use in transformer: content: stripHtml(w.htmlContent)Best practices
- Use a dedicated Mural service account to generate the integration token, ensuring the integration does not break if an individual team member's account is deactivated or their password changes
- Store the Mural access token in a Retool Configuration Variable marked as a secret — never paste the raw token into resource configuration fields or JavaScript query bodies where it could be logged
- Add cursor-based pagination handling to the murals list query, as workspaces with many boards will return paginated results — check for a 'next' cursor field in the API response and implement a 'Load More' button
- Build color-to-theme label mappings specific to your team's workshop templates, transforming hex color codes into meaningful theme names (e.g., 'Problems', 'Solutions', 'Unknowns') for non-technical stakeholders
- Cache mural list queries for 60 seconds using Retool's query caching feature, since workspace mural lists change infrequently and caching reduces API calls on busy dashboards
- Pair the Mural dashboard with a connected database (PostgreSQL or Retool Database) to persist workshop outcomes, decisions, and next steps — Mural's own API does not store annotations or classifications added in Retool
- Test the integration with a small sandbox mural board containing 10-20 sticky notes before connecting to large production boards with hundreds of widgets, to validate your transformer logic handles all content formats
Alternatives
Miro is the more widely-used general-purpose whiteboard with a richer REST API and native Retool examples — choose Miro if your team uses it as the primary whiteboard tool rather than Mural specifically for structured facilitation.
Lucidchart focuses on structured diagramming and flowcharts rather than freeform workshop facilitation — choose Lucidchart when your use case is extracting diagram data and shapes rather than sticky note aggregation.
Notion's API provides direct access to structured database and page data without needing to extract content from a visual canvas — choose Notion if your team already documents workshop outcomes in Notion pages or databases.
Frequently asked questions
Does Retool have a native Mural connector?
No, Retool does not have a native Mural connector. You connect via a REST API Resource using Mural's public API v1 with Bearer token authentication. The setup takes approximately 25 minutes and gives you full access to mural boards, widget data, workspace members, and room listings.
Can I create new sticky notes or murals in Mural from Retool?
Yes, if your personal access token or OAuth app includes the murals:write scope. Use a POST request to /murals/{muralId}/widgets with the widget type, content, position, and styling properties in the JSON body. You can also create new murals in a room using POST /rooms/{roomId}/murals. This enables Retool forms to populate Mural boards with structured data — for example, creating a prioritization board from a CSV upload.
What is the Mural API rate limit and how do I stay within it?
Mural's public API enforces a rate limit of approximately 100 requests per minute per token. For Retool dashboards that load multiple queries simultaneously, use event handlers to trigger queries sequentially (on app load → getWorkspaceMurals, then on row select → getMuralWidgets) rather than running all queries at once. Enable Retool's query caching (60-second TTL) on the mural list query to reduce repeated requests when users switch between views.
Can I access all murals across my entire Mural organization from Retool?
You can access murals within workspaces that the token-generating account belongs to. List workspaces using GET /workspaces, then iterate through rooms with GET /workspaces/{workspaceId}/rooms, and finally list murals per room. The account must have at least Viewer access to each workspace to see murals within it — company-level admin access allows querying across all workspaces.
How do I handle Mural boards with hundreds of sticky notes in Retool?
Mural's widget endpoint supports a limit parameter (up to 200 per request) and a cursor-based pagination via the 'next' token in the response. For large boards, implement a 'Load All' pattern using a Retool Workflow that iterates through all pages of widgets, accumulates results, and stores them in a Retool Database table for querying — rather than pulling all widgets on every dashboard load.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation