What Is Dev Tools?
Dev Tools is a floating debugging window built into the UnifyApps page builder and Preview. It gives you live visibility into everything happening inside your app as you interact with it — events firing, actions executing, data sources fetching, state changing, and errors occurring.


Dev Tools is a development tool. You can use it in the builder and in Preview. It never appears in the published app and has no effect on your app's production behavior. It exists solely to help you understand, trace, and debug your app's logic during development.
Note: Not in the published app Dev Tools never appears in your published app. End users will never see it. You can leave Dev Tools open while you build without any concern about it affecting what your users experience.
Opening Dev Tools
You can open Dev Tools in three ways:
In the builder, click the Dev Tools icon in the left icon rail.
In Preview, click the Dev Tools toggle in the top bar.
Use the keyboard shortcut
Alt + Shift + Dfrom anywhere in the builder or Preview.
Window Management
The Dev Tools window is a freely floating panel that sits in front of the canvas. It does not dock to any edge of the builder.
Action | How to do it |
|---|---|
Move the window | Click and drag the window's header bar to reposition it anywhere over the canvas. |
Resize the window | Click and drag the grip handle in the bottom-right corner of the window to resize it. |
Reset position | Click the reset icon in the window header (Reset window to default position) to return the window to its default position and size. |
Minimize | Hide the window while Pulse keeps recording — no data is lost. Click Dev Tools in the left rail (or press |
Close | Fully close the Dev Tools window. Closing stops Pulse recording and clears all captured events. The next time you open Dev Tools, the stream starts fresh. Error counting for the rail badge keeps running while the window is closed. |
The window's layout — its position, size, and which tab was last open — persists across page refreshes within the same session. If you navigate to a different page in the builder, Dev Tools reopens in the same position showing the last tab you used.
Warning: Minimize vs. Close These two actions have very different consequences. Minimize keeps recording running silently — Pulse captures all events even while the window is hidden. Close stops recording entirely and discards all captured events. Choose Close only when you are done debugging a particular issue.
The Four Tabs
Dev Tools has four tabs, each providing a different lens on your app's runtime behavior:
| Tab | Description |
| Pulse | The app-level event stream. Shows a chronological, readable log of everything that happens as you interact with the app — events, actions, state changes, data fetches, errors, and custom log messages. |
| Console | Mirrors the browser's developer console output. Useful for seeing console.log output from custom JavaScript in your app and for browser-level warnings and errors. |
| Network | Shows raw network requests made by the app — API calls, data source fetches, and other HTTP traffic. Useful for verifying request payloads and response bodies. |
| State | A browsable, real-time snapshot of all page state. Shows variables, data source results, component outputs, and global context values at the current moment. |
Pulse — The Event Stream
The Pulse tab is the most powerful debugging tool in Dev Tools. It captures every significant thing that happens in your app and presents it as a readable, structured feed you can trace step by step.
The 7 event kinds Pulse records
Kind | What it represents | Example message |
|---|---|---|
Event | A user interaction or system event that fired on a component (e.g., On Click, On Change, On Load). | "On Click fired on submitButton" |
Action | An action that ran as part of an event handler chain — API call, navigate, show modal, set variable, etc. | "Set |
Component method | A method called on a specific component instance — e.g., | "Called |
State change | A change to the app's state store — a variable updated, a data source result stored, etc. | "Changed from |
Data source | A data source fetch lifecycle event — fetch started, completed, or skipped. Combines what would otherwise be two separate rows (fetch + store update) into one. | "Fetch completed — 24 rows returned" / "Fetch skipped — the run condition evaluated to false" |
Error | An error that occurred during event processing, action execution, or a data source fetch. Highlighted in red. | "Script error in |
Log | A custom log message emitted by a Log to debugger action in your app's event handlers. Used for developer-authored debug output. | "[DEBUG] form submitted with payload: {…}" |
Stream columns
Each row in the Pulse stream has several columns. The columns are resizable — drag the column header divider to adjust column widths.
Column | Description |
|---|---|
# | Sequence position of the event in the current capture session. Useful for referencing specific events in discussion. |
Scope | Where in the app the event originated. This column is only shown when there are events from multiple scopes in the stream — for example, events from different pages or embedded components. Drag to resize. |
Time | The time the event happened (your local time, HH:mm:ss). Drag to resize. |
Kind | The event type — one of the 7 kinds listed above, shown as a colored badge. Drag to resize. |
Entity | The component, variable, data source, or function involved in the event. Drag to resize. |
Message | A human-readable description of what happened, for example "Changed from {old} to {new}", "Changed {field} from {old} to {new}", "Set {field} to {value}", "Changed {fields}" (when several fields change at once, the message lists their names) or "Fetch completed successfully in 101ms". This is the primary column for understanding what occurred. |
Filtering and searching the stream
The filter bar above the stream accepts both structured filters and free-text search. The placeholder text reads: "Filter by scope, kind, entity — or search messages…"
Click in the filter bar to open a dropdown showing available filter keys (scope, kind, entity) grouped under "Filters", with specific values listed as "Suggestions". Selecting a filter adds a chip to the bar. Multiple chips narrow the stream to rows matching all applied filters simultaneously.
Typing text that does not match a filter key performs a free-text search across event messages. Press Enter to apply the search as a chip. Each applied filter or search term appears as a dismissible chip in the filter bar.
A Clear filters button appears when any filters or searches are active, removing all chips at once.
Keyboard-driven filtering
The filter bar is fully keyboard-navigable:
Arrow keys — Navigate through suggestions in the dropdown.
Enter — Apply the selected suggestion as a filter chip, or apply typed text as a free-text search chip.
Escape — Close the suggestion dropdown without applying a filter.
Backspace — Remove the last applied chip when the input field is empty.
Pause and resume capture
The Pulse stream captures events continuously by default. A Pause/Resume toggle in the toolbar lets you freeze the stream when you want to examine what was captured without new events scrolling past. While paused, Pulse doesn't record new events; what was already captured stays on screen. Resume to start recording again.
A Clear button discards all currently captured events and resets the stream to empty.
The footer bar at the bottom of the Pulse tab shows the current state: either "Live" (capturing) or "Paused", and how many rows are currently showing.
Consecutive event grouping
Repeated changes to the same value within one second are folded into a single row rather than flooding the stream. The row shows the most recent change, and a count badge such as ×2 appears next to its Kind. Hovering over the grouped row or its badge reveals a tooltip: "N identical consecutive events grouped", where N is the total count including the grouped ones. Other event kinds, such as On Click or On Change event rows, are never grouped.
Tip: Event grouping and text inputs If you type in a text input and notice only one state change row where you expected many, the changes it wrote to state may be grouped. Hover the row to check the grouped count.
Event Details Panel
Clicking any row in the Pulse stream opens the Event Details panel on the right side of the Dev Tools window. This panel provides deep context about the selected event through four tabs:
| Tab | What it shows |
| Payload | The data carried by the event — the event arguments, action inputs, or component output values at the moment the event fired. Shown as an expandable JSON tree. |
| Error | Error details if the event resulted in a failure. The tab header is visually highlighted (red indicator) when an error is present, making failed steps immediately visible without needing to click. Shows the error message, source, and full stack trace with a Copy button. |
| State | A snapshot of all page state at the exact moment this event was captured. Identical in structure to the dedicated State tab but frozen to this point in time — useful for seeing what state values were when the event fired. |
| Changes | A before/after diff of state changes that resulted from this event. A badge on the tab header shows the count of changed state fields. If no state changed, shows "No store change for this step". If state was not captured for this step, shows "No state captured". |
Data Source Event Messages
Data source events appear as a single row in Pulse (rather than separate "fetch started" and "store updated" rows). The message follows a consistent format based on the outcome:
Outcome | Message format |
|---|---|
Success | "Fetch completed successfully" — shown when the result is not a countable array. When the duration is known, it is added: "Fetch completed successfully in 101ms". |
Success — with count | "Fetch completed — N rows returned" — shown when the result is an array. When the duration is known, it is added: "Fetch completed — N rows returned in 342ms". |
Failure | "Fetch failed — data could not be retrieved" — the row is marked as an error. Click to open the Error tab in the Event Details panel for the full error message and stack trace. |
Skipped — cached | "Fetch skipped — reusing a cached response, inputs are unchanged" — the inputs are the same as last time, so a cached response was reused and no request was made. No action is needed. |
Skipped — disabled | "Fetch skipped — the data source is currently disabled" |
Skipped — run condition | "Fetch skipped — the run condition evaluated to false" — the data source has a run condition that evaluated to false, so no network request was made. |
Skipped — duplicate request | "Fetch skipped — an identical request is already in progress" |
Skipped — not ready | "Fetch skipped — the data source is not yet ready to fetch" |
Skipped — no specific reason | "Fetch skipped — inputs have not changed since the last fetch" — the general skip message. It is shown when none of the reasons above (cached, disabled, run condition, duplicate request, not ready) is reported. |
Error Events
When something goes wrong, Pulse highlights the row in red so it stands out immediately. Error rows come from the three sources below. Failed data source fetches and failed actions are also marked red, on their own Data source and Action rows.
| Error type | Description |
| Script error | An unhandled JavaScript exception in custom JavaScript code in your app (e.g., in a JS action, a custom function, or a computed expression). |
| Page function error | An error in a page-level function defined in the page's function library. |
| Action error | An error that occurred during the execution of an action in an event handler — for example, an API call that returned an error status, or a navigate action that failed to resolve the target. |
Clicking an error row opens the Event Details panel. The Error tab shows:
The full error message.
A Copy button to copy the error to the clipboard.
The Source — the event handler, function, or action where the error originated.
The full stack trace for JavaScript errors.
Note: Error count badge on the rail icon Error counting runs separately from Pulse recording. Even when the Dev Tools window is closed, the Dev Tools icon in the left rail shows a red badge with the number of errors captured, including failed actions and failed data source fetches. You can spot errors without keeping Dev Tools open. Closing the Dev Tools window clears the count, and errors that happen afterwards are counted again. The count also resets when you reload the builder or open a different app.
State Tab — App State Snapshot
The State tab provides a real-time, browsable snapshot of all state in your app at the current moment. Unlike the State sub-tab in Event Details (which is frozen to a past event), the State tab always reflects the current live state.
State is organized into groups
The left sidebar of the State tab groups state into logical categories:
| Group | What it contains |
| Variables | All page-level and global variables, with their current values. |
| Functions | Page-level functions defined in the function library. |
| Data sources | The current results, loading state, and error state of every data source configured on the page. |
| Blocks | The output values and state of reusable block components on the page. |
| Global | App-wide context that is available on every page. Includes: environment variables, the logged-in user's profile, the current location (URL, page, params), the app record, and session storage values. |
Browse and Raw views
A Browse / Raw toggle at the top of the State tab switches between two display modes:
Browse — An expandable tree view of state, formatted for readability. Expand nested objects and arrays to inspect individual fields.
Raw — The full state as a raw JSON string. Useful when you want to copy the entire state snapshot or search for a specific value with the browser's find function.
Empty State Messages
The Pulse stream shows contextual messages when no events are visible, depending on the reason:
"No events yet — Interact with your app to generate events" — Dev Tools has just been opened and nothing has happened yet. This is the initial state. Click buttons, fill forms, or trigger any interaction on the canvas to start the stream.
"No events found — Try adjusting your filters or search term" — Events have been captured, but the current filter/search combination matches nothing. Clear or adjust your filters to see events.
Event Capacity
Pulse keeps the most recent 500 events in memory. When the stream reaches capacity, the oldest events are dropped as new ones arrive. For long debugging sessions with high event volume, periodically clear the stream (using the Clear button) and reproduce the specific issue you are investigating to keep the relevant events in view.
Warning: 500-event limit If you have actions that fire frequently (for example, On Mouse Move or On Scroll handlers), the stream can fill up quickly. Consider adding a filter for the specific event kind or entity you are debugging so the stream only shows relevant events and does not fill with noise.
Debugging Workflow Tips
Tracing an action chain
When a button click should trigger multiple actions in sequence, use Pulse to verify each step ran:
Open Dev Tools and go to the Pulse tab: Press
Alt + Shift + Dto open Dev Tools. Confirm Pulse is selected and recording ("Live" shows in the footer).Trigger the interaction: Click the button (or trigger the event) on the canvas. Enable Interactive Canvas mode with
Cmd/Ctrl + Shift + Eif needed to allow click-throughs.Review the event sequence in Pulse: Look for the Event row that matches your trigger, then trace the Action rows that follow. Each action should appear in order. If the chain stops early, the last row before the gap (or the first Error row) identifies where it failed.
Click any row for details: Click the row before the gap to open Event Details. Check the State tab to see the state when that step ran, the Changes tab to see what it changed, and the Error tab if the row is highlighted in red.
Debugging data source issues
Filter the Pulse stream by Kind = "Data source" to see only data source events. Look for:
Skip messages — If a fetch is being skipped unexpectedly, read the skip reason in the message (for example, "Fetch skipped — the run condition evaluated to false" or "Fetch skipped — the data source is currently disabled"). See the table above for all skip reasons. Open Event Details to check the payload, which will show the state values that were evaluated.
Zero rows returned — "Fetch completed — 0 rows returned" confirms the request succeeded but the query returned no data. This narrows the issue to the data source query itself rather than a connection or action problem.
Fetch failed — An Error row with the response body in the Error tab. Check the status code, error message, and whether the API credentials or endpoint URL are correct.