Connect Retool to Asana using a REST API Resource with a personal access token. Configure the base URL and authorization header in Retool's Resources tab, then build cross-project dashboards that aggregate tasks, track deadlines, manage assignees, and generate executive-level project status reports across all workspaces — giving operations and leadership teams views that Asana's native interface can't produce.
| Fact | Value |
|---|---|
| Tool | Asana |
| Category | Productivity |
| Method | REST API Resource |
| Difficulty | Intermediate |
| Time required | 25 minutes |
| Last updated | April 2026 |
Build Cross-Project Operations Dashboards with Asana and Retool
Asana is excellent for individual project management, but operations and leadership teams often need views that span multiple projects, portfolios, or workspaces simultaneously. Asana's native Portfolio and Reporting features require Enterprise plans and still have limitations for custom metrics. Retool connected to Asana's API removes these constraints: you can query tasks across every project simultaneously, calculate custom metrics with JavaScript transformers, join Asana task data with information from other systems (CRM, databases, JIRA), and display the results in rich dashboards with Charts, Gantt-style Tables, and filtered views.
Asana's REST API v1 exposes the full data model: workspaces, teams, projects, sections, tasks, subtasks, tags, users, portfolios, goals, and custom fields. Every object is identified by a globally unique ID (GID). The API's design requires you to first enumerate workspace GIDs, then project GIDs within workspaces, and finally task GIDs within projects — a hierarchical traversal that Retool handles through chained queries.
The most impactful patterns for Retool-Asana integrations are cross-project task dashboards for department heads, portfolio health reports for program managers, deadline tracking systems that alert on overdue tasks across all projects, and operations panels where support or success teams create Asana tasks directly from Retool without needing Asana licenses. These use cases are difficult or impossible to achieve from within Asana's own interface.
Integration method
Asana integrates with Retool through Asana's REST API v1, configured as a REST API Resource. Authentication uses a personal access token sent as a Bearer token header. The Asana API uses a consistent query pattern where you first fetch workspace and project GIDs, then use those GIDs to query tasks, portfolios, and users. Retool proxies all requests server-side, and the ASANA-ENABLE and ASANA-DISABLE headers manage API feature flags for pagination and response formatting.
Prerequisites
- An Asana account with access to the projects and workspaces you want to query
- An Asana personal access token generated from asana.com/0/my-apps (for individual use) or OAuth app credentials (for team deployment)
- The GID of your Asana workspace, available in your Asana URL or via the /workspaces endpoint
- A Retool account with permission to create Resources
- Knowledge of which Asana projects and portfolios you want to surface in Retool
Step-by-step guide
Generate an Asana personal access token
Go to asana.com and sign in. Click your profile picture in the top right, select 'My Profile Settings', then click the 'Apps' tab. Scroll down to 'Developer Apps' and click 'Manage Developer Apps'. Click 'New Access Token', give it a descriptive name like 'Retool Dashboard', and click 'Create Token'. Asana displays the access token once — copy it immediately and store it in a password manager. This token authenticates as you and has access to everything your Asana user account can see: all workspaces, teams, projects, and tasks you're a member of or have been granted access to. For team deployments where multiple Retool users need access to shared Asana projects, consider using Asana's OAuth 2.0 app authentication instead. This requires creating an Asana developer application at asana.com/0/developer-console, configuring OAuth credentials, and setting up per-user authentication in Retool. For most internal tool use cases, a shared service account token (if permitted by your Asana admin) is simpler and more practical. Note your workspace GID as well — you'll need it for queries that require workspace context. To find it, open any Asana task URL: the number appearing as the first segment after 'app.asana.com/0/' is your workspace GID.
Pro tip: Personal access tokens don't expire but can be revoked at any time from the Apps settings page. For production Retool dashboards, use a dedicated service account in Asana rather than a personal account token — this ensures the token remains valid even if the original user leaves the organization.
Expected result: You have an Asana personal access token copied and stored securely. You know your workspace GID for scoping queries.
Configure the Asana REST API Resource in Retool
In Retool, go to the Resources tab and click 'Create a resource'. Select 'REST API'. Name it 'Asana API'. Set the base URL to https://app.asana.com/api/1.0. This is Asana's stable API v1 base URL — all query paths are relative to this. For authentication, select 'Bearer Token'. Paste your Asana personal access token in the token field. Retool will send Authorization: Bearer {token} with every request. Add a custom header to help Asana format responses correctly. Click 'Add header' and set the name to asana-enable with the value new_user_task_lists,new_project_templates. This enables newer API behaviors for the Asana API and prevents deprecation warnings in responses. Also add Accept: application/json to ensure JSON responses. Save the resource. Since personal access tokens don't expire, there's no OAuth flow to complete — the resource is ready to use immediately. For team environments, store the Asana token in a Retool configuration variable (Settings → Configuration Variables, mark as secret) and reference it in the Bearer Token field as {{ retoolContext.configVars.ASANA_TOKEN }}. This lets you rotate the token without updating every Resource.
Pro tip: Asana's API rate limit is 1,500 requests per minute for personal access tokens and 150 requests/minute per OAuth app. For dashboards that query many projects or tasks, use the opt_fields parameter to minimize response size and consider query caching to reduce API calls.
Expected result: The Asana API resource is configured in Retool with Bearer authentication. The resource is ready to use without any OAuth flow.
Fetch workspaces and projects to understand the data model
Start by querying Asana's top-level resources to understand what's available. Create a query named 'getWorkspaces' with GET method and path /workspaces. This returns all workspaces your token can access. Run it and note the GID of the workspace you want to query — copy the GID value for use in subsequent queries. Next, create a query 'getProjects' with GET method and path /projects. Add URL parameters: workspace (set to your workspace GID), archived (set to false to exclude archived projects), and opt_fields (set to gid,name,color,current_status,due_on,owner,owner.name,permalink_url). The opt_fields parameter is critical for Asana — without it, most queries return only GID and name, and additional fields require a separate request per object. Asana's API returns paginated results using a cursor-based pagination system. The response body has a 'data' array and optionally a 'next_page' object with an 'offset' cursor string. Add a limit parameter set to 100 (Asana's maximum) and implement pagination by passing the offset cursor in subsequent requests. Create a third query 'getProjectTasks' with GET method and path /tasks. Add URL parameters: project (set to {{ projectsTable.selectedRow?.gid || '' }}), completed_since (set to 'now' to get incomplete tasks or a specific date string), and opt_fields (set to gid,name,assignee,assignee.name,due_on,completed,notes,custom_fields,memberships,tags,permalink_url). Run this query after selecting a project row.
1// JavaScript transformer for Asana tasks response2const tasks = data.data || [];34return tasks.map(task => {5 // Extract custom field values (custom fields vary by project)6 const customFields = {};7 (task.custom_fields || []).forEach(cf => {8 const value = cf.type === 'enum' ? cf.enum_value?.name9 : cf.type === 'number' ? cf.number_value10 : cf.type === 'text' ? cf.text_value11 : cf.type === 'date' ? cf.date_value12 : cf.display_value;13 customFields[cf.name] = value || '';14 });15 16 const dueDate = task.due_on ? new Date(task.due_on) : null;17 const today = new Date();18 const isOverdue = dueDate && !task.completed && dueDate < today;19 const daysUntilDue = dueDate20 ? Math.ceil((dueDate - today) / (1000 * 60 * 60 * 24))21 : null;2223 return {24 gid: task.gid,25 name: task.name,26 assignee: task.assignee?.name || 'Unassigned',27 dueOn: task.due_on || '',28 daysUntilDue,29 isOverdue,30 completed: task.completed,31 priority: customFields['Priority'] || '',32 status: customFields['Status'] || '',33 notes: task.notes ? task.notes.substring(0, 100) + (task.notes.length > 100 ? '...' : '') : '',34 url: task.permalink_url35 };36});Pro tip: The opt_fields parameter is the most important performance optimization for Asana API queries. Always specify exactly the fields you need — without it, Asana returns minimal data and each missing field requires a separate API call, rapidly consuming your rate limit.
Expected result: You can query workspaces, projects, and tasks. The transformer flattens Asana's nested structure into display-ready objects. Custom field values are accessible by name.
Build the cross-project task overview
Build a multi-project task dashboard. The challenge is that Asana's task endpoint queries one project at a time — to build a cross-project view, you need to query multiple projects and aggregate results using a JavaScript query. Create a JavaScript query named 'getAllProjectTasks'. In the query body, use Promise.all() to query tasks from multiple project GIDs simultaneously, then merge and sort the results. Reference the projects query to get all project GIDs dynamically. For the UI, add a Select component at the top for filtering by project, an Assignee Select filter, a Date Range picker for due date filtering, and a Toggle for 'Show overdue only'. Connect these filters to your task transformer using {{ }} expressions. Add a Table component showing the transformed task data. Configure columns: name (with a link to task.url), project (if showing cross-project data), assignee (as a Tag), dueOn (formatted), isOverdue (as conditional row styling — red background for overdue tasks), priority, and status. Above the table, add three Statistic components: Total Tasks, Overdue Tasks (tasks where isOverdue is true), and Tasks Due This Week. These give the executive-level summary at a glance. For charts, add a Bar Chart showing task count by assignee, and a second chart showing tasks by due date distribution to visualize workload concentration.
1// JavaScript query to aggregate tasks across multiple projects2const projectGids = getProjects.data?.data?.map(p => p.gid) || [];34if (projectGids.length === 0) return [];56// Query tasks for each project in parallel (up to 10 projects)7const projectsToQuery = projectGids.slice(0, 10);89const results = await Promise.all(10 projectsToQuery.map(projectGid =>11 getProjectTasks.trigger({ additionalScope: { overrideProjectGid: projectGid } })12 .then(result => (result.data || []).map(task => ({13 ...task,14 projectGid,15 projectName: getProjects.data?.data?.find(p => p.gid === projectGid)?.name || ''16 })))17 .catch(() => []) // Handle individual project failures gracefully18 )19);2021// Flatten all project results into one array and sort by due date22return results.flat().sort((a, b) => {23 if (!a.due_on) return 1;24 if (!b.due_on) return -1;25 return new Date(a.due_on) - new Date(b.due_on);26});Pro tip: Querying more than 10-15 projects simultaneously will hit Asana's rate limits. For organizations with many projects, use a Retool Workflow on a schedule to pre-fetch and cache task data in a Retool Database table, then have the dashboard query the local cache instead of live Asana API calls.
Expected result: The dashboard shows tasks aggregated across multiple Asana projects with filtering by project, assignee, and due date. Overdue tasks are highlighted in red. Summary statistics show total, overdue, and upcoming tasks.
Add task creation and update capabilities
Enable the Retool dashboard to create and update Asana tasks. Create a query named 'createTask' with POST method and path /tasks. The request body must include the workspace or project GID, task name, and optional properties. Build a Retool Form component for task creation. Add fields: Task Name (TextInput, required), Project (Select, populated from getProjects), Section (Select, populated based on project selection), Assignee (Select, populated from team members), Due Date (DatePicker), Priority (Select for custom field), and Description (TextArea). Connect the Form's submit button to the createTask query. For task updates, add inline editing to the tasks Table component: enable 'Save changes' mode and create an 'updateTask' query with PUT method and path /tasks/{{ tasksTable.selectedRow?.gid }}. The update body only needs the changed fields — Asana supports partial updates. For marking tasks complete, add a 'Mark Complete' action button in the table. This triggers a PUT to /tasks/{gid} with body { "completed": true }. Add a confirmation modal since completing tasks in Asana notifies assignees and followers. For complex Asana integrations with portfolio management, custom fields, rules automation, and cross-workspace reporting, RapidDev's team can help build the complete operations system.
1// POST /tasks — Create a new Asana task2{3 "data": {4 "name": "{{ taskNameInput.value }}",5 "notes": "{{ taskDescriptionInput.value }}",6 "assignee": "{{ assigneeSelect.value || null }}",7 "due_on": "{{ taskDueDatePicker.value || null }}",8 "projects": ["{{ projectSelect.value }}"],9 "memberships": [{10 "project": "{{ projectSelect.value }}",11 "section": "{{ sectionSelect.value || null }}"12 }],13 "custom_fields": {14 "{{ priorityFieldGid }}": "{{ prioritySelect.value }}"15 }16 }17}Pro tip: To set custom field values when creating tasks, you need the custom field's GID (not its name). Query /projects/{project_gid}/custom_field_settings to get the GID-to-name mapping for each project's custom fields, then use the GID as the key in the custom_fields object.
Expected result: The Retool app can create new Asana tasks via a form, mark tasks complete, and update task properties inline. New tasks appear in Asana immediately with all required properties set.
Common use cases
Executive cross-portfolio project status dashboard
Build a dashboard that queries all portfolios visible to the authenticated user, calculates completion percentages and overdue task counts for each portfolio, and displays a grid of project health cards showing RAG (red/amber/green) status. Leadership gets a real-time view of all programs without navigating through Asana's portfolio hierarchy.
Build a Retool app querying all Asana portfolios and their contained projects. Calculate completion percentage (completed tasks / total tasks) and overdue task count per project. Display a Table with project name, portfolio, owner, deadline, completion %, overdue count, and a status tag (green/yellow/red). Add a Date Range filter and click-through to project task details.
Copy this prompt to try it in Retool
Department task backlog and assignment panel
Build a team task management panel that shows all incomplete tasks assigned to team members across all department projects. Group by assignee, show due dates, enable bulk reassignment, and allow filtering by project or section. This gives managers visibility into individual workloads without Asana's premium seats.
Build a Retool dashboard querying all tasks in a specific Asana workspace assigned to team members in the Engineering department. Group by assignee and show total task count, overdue count, and a Table of tasks with name, project, due date, priority, and a reassign button. Include a 'Create Task' form.
Copy this prompt to try it in Retool
Operations request intake and task creation panel
Build an internal request intake form where non-technical staff submit work requests that automatically create Asana tasks with the correct project, section, assignee, and custom fields pre-populated. This eliminates direct Asana access for large teams while maintaining task tracking through Asana.
Build a Retool form for submitting IT support requests. Fields: request type (Select), description, priority, requested deadline, and requester name. On submit, create an Asana task in the IT Operations project, assign to the correct queue based on type, and show a confirmation with the task URL. Display a 'My Recent Requests' table showing past submissions.
Copy this prompt to try it in Retool
Troubleshooting
Asana API queries return only GID and name for tasks, missing fields like assignee, due_on, and custom_fields
Cause: Asana's API returns only GID and name by default unless you specify additional fields using the opt_fields parameter.
Solution: Add the opt_fields URL parameter to your task queries listing every field you need, comma-separated. For a comprehensive task view, use: gid,name,assignee,assignee.name,due_on,completed,notes,custom_fields,custom_fields.name,custom_fields.display_value,permalink_url. Without opt_fields, Asana's API is intentionally minimal to reduce payload size.
Asana returns 429 Too Many Requests when loading a cross-project dashboard
Cause: Querying tasks from many projects simultaneously exceeds Asana's rate limit of 1,500 requests/minute for personal access tokens or 150 requests/minute for OAuth apps.
Solution: Limit parallel project queries to 5-10 projects per page load. Add a Select component to let users choose which projects to load rather than loading all at once. For dashboards requiring data from many projects, use a Retool Workflow on a schedule (every 15 minutes) to pre-fetch task data into a Retool Database table and serve the dashboard from cached data.
Creating a task returns 400 Bad Request with 'Invalid Request: No workspace or organization provided'
Cause: Task creation requires either a workspace GID, a project GID (which implies the workspace), or an assignee (which Asana can infer the workspace from). Without at least one of these, Asana can't determine which workspace to create the task in.
Solution: Include at least one of: the workspace parameter (workspace GID), the projects array (with at least one project GID), or the assignee (a user GID within a known workspace). The simplest fix for a form-based task creator is always requiring the project selection and including it in the request body.
1// Minimum required body for task creation2{3 "data": {4 "name": "{{ taskNameInput.value }}",5 "projects": ["{{ projectSelect.value }}"]6 }7}Asana pagination only returns the first 100 tasks even when a project has more
Cause: Asana paginates results with a maximum of 100 items per page. Without handling the next_page cursor in responses, only the first page is displayed.
Solution: Check the query response for a 'next_page' object containing an 'offset' string. Pass this offset as a URL parameter in the next request to retrieve subsequent pages. For complete datasets, implement recursive fetching in a Retool Workflow or JavaScript query, accumulating results until next_page is null. For dashboards, implement explicit 'Load more' pagination rather than loading all records at once.
Best practices
- Always use the opt_fields parameter in Asana queries — it's the single most important optimization for performance and rate limit efficiency; specify only the fields your UI actually displays
- Store frequently-queried workspace and project GIDs in Retool configuration variables rather than hardcoding them in query parameters — this makes the app easier to configure for different teams
- Use Retool query caching with a 5-minute TTL for project and user lists that change infrequently — task lists can have shorter or no caching if real-time accuracy is important
- Implement a 'last updated' indicator showing when cross-project task data was last fetched, and add a manual 'Refresh' button rather than auto-refreshing frequently to stay within rate limits
- For task creation forms, pre-populate the Project and Assignee selects using live Asana data rather than hardcoding options — this ensures the form stays current as projects and team members change
- Use Asana's search API (/tasks/search with text parameter) for full-text task search across the workspace rather than loading all tasks and filtering in JavaScript — this is significantly faster for large workspaces
- When building dashboards for multiple teams using the same Retool app, parameterize the workspace and project GIDs via URL parameters so different team URLs load different Asana projects automatically
Alternatives
Choose Jira if your engineering team uses Jira for sprint management — Jira has a native Retool connector with JQL query support, whereas Asana requires a REST API Resource configuration.
Choose ClickUp if you need deeper custom field support and more granular task hierarchies — ClickUp's API provides more flexible query options for teams with complex custom workflow states.
Choose Monday.com if your team relies on its visual board interface and integrations — Monday.com's GraphQL API enables complex cross-board queries with robust automation triggers.
Frequently asked questions
Can I use a single Asana personal access token for a shared Retool team dashboard?
Yes. If you configure the Asana Resource with 'Share credentials between users' enabled and use a service account's token, all Retool users will authenticate as that service account. Ensure the service account has member access to all required Asana workspaces and projects. Personal access tokens don't expire, so this approach works well for production dashboards — just rotate the token periodically for security.
Does Retool's Asana integration support Asana Portfolios and Goals?
Yes, Asana's API exposes portfolios via the /portfolios endpoint and goals via the /goals endpoint. Both require querying by workspace GID first. Portfolio items (projects within portfolios) are accessed via /portfolios/{portfolio_gid}/items. You can build executive dashboard views over portfolios using the same REST API Resource — add opt_fields to include portfolio-level custom fields and status updates.
Why does Asana's API require so many separate requests to get complete data?
Asana's API is designed for efficiency — by default it returns minimal fields to reduce payload size and server load. The opt_fields system allows clients to request exactly the data they need. While this requires more thought in query design, it means Asana queries are faster and consume less rate limit than APIs that return complete objects regardless of what the client needs. Use opt_fields carefully and you'll find the performance excellent.
Can I trigger Asana rules or automations through the API?
Creating or updating tasks through Asana's API will trigger any rules set up in Asana that respond to those events (e.g., 'When task is created → assign to team member' or 'When due date passes → add tag'). You don't need to explicitly trigger rules — they fire based on the data changes your API calls make. However, you cannot directly invoke Asana rules via the API.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation