[go: up one dir, main page]

Deep linking to the Perfetto UI

This document describes how to open traces hosted on external servers with the Perfetto UI. This can help integrating the Perfetto UI with custom dashboards and implement 'Open with Perfetto UI'-like features.

In this guide, you'll learn how to:

You'll also learn how to customize the UI state when opening traces (zoom, selection, queries).

Option 1: Direct URL for public traces

If your trace is publicly accessible via HTTPS, you can link directly to it using the url query parameter:

https://ui.perfetto.dev/#!/?url=https://example.com/path/to/trace.pftrace

Requirements:

This is the easiest option for publicly hosted traces that don't require authentication or custom sharing features.

Limitations:

If you need any of these features, use Option 2 instead.

Option 2: Using postMessage for full control

For traces that require authentication, custom sharing URLs, or other advanced features, use the postMessage approach. This requires some JavaScript code running on infrastructure you control.

Step 1: Open ui.perfetto.dev via window.open

The source dashboard (the one that knows how to locate a trace and deal with ACL checking, OAuth authentication, etc.) creates a new tab:

var handle = window.open('https://ui.perfetto.dev');

The window handle allows bidirectional communication using postMessage() between your dashboard and the Perfetto UI.

Step 2: Wait for the UI to be ready via PING/PONG

The window.open() message channel is not buffered. If you send a message before the opened page has registered an onmessage listener, the message will be dropped. To avoid this race condition, use a PING/PONG protocol: keep sending 'PING' messages until the opened window replies with 'PONG'.

Step 3: Post the trace data

Once the PING/PONG handshake is complete, post a message to the Perfetto UI window. The message should be a JavaScript object with a single perfetto key:

{ 'perfetto': { buffer: ArrayBuffer; title: string; fileName?: string; // Optional url?: string; // Optional appStateHash?: string // Optional } }

The properties of the perfetto object are:

Sharing traces and UI state

When traces are opened via postMessage, Perfetto avoids storing the trace as doing so may violate the retention policy of the original trace source. The trace is not uploaded anywhere. Thus, you must provide a URL that provides a direct link to the same trace via your infrastructure, which should automatically re-open Perfetto and use postMessage to supply the same trace.

The url and appStateHash properties work together to allow users to share a link to a trace that, when opened, restores the trace and the UI to the same state (e.g., zoom level, selected event).

When a user clicks the "Share" button in the Perfetto UI, Perfetto looks at the url you provided when opening the trace. If this url contains the special placeholder perfettoStateHashPlaceholder, Perfetto will:

  1. Save the current UI state and generate a unique hash for it.
  2. Replace perfettoStateHashPlaceholder in your url with this new hash.
  3. Present this final URL to the user for sharing.

For example, if you provided this url: 'https://my-dashboard.com/trace?id=1234&state=perfettoStateHashPlaceholder'

Perfetto might generate a shareable URL like this: 'https://my-dashboard.com/trace?id=1234&state=a1b2c3d4'

When another user opens this shared URL, your application should:

  1. Extract the state hash (a1b2c3d4 in this example) from the URL.
  2. postMessage the trace buffer as usual, but this time also include the appStateHash property with the extracted hash.

Perfetto will then load the trace and automatically restore the UI state associated with that hash.

If the url property is omitted, the share functionality will be disabled. If the perfettoStateHashPlaceholder is omitted from the url, the trace can be shared but the UI state will not be saved.

Code samples

See this example caller, for which the code is in this GitHub gist.

Googlers: take a look at the existing examples in the internal codesearch.

Common pitfalls

Many browsers sometimes block window.open() requests, prompting the user to allow popups for the site. This usually happens if:

If the trace file is big enough, the fetch() might take long enough to exceed the user gesture threshold. This can be detected by observing that window.open() returned null. When this happens, the best option is to show another clickable element and bind the fetched trace ArrayBuffer to the new onclick handler, like the code in the example above does.

Some browsers have a variable time threshold for the user gesture timeout which depends on the website engagement score (how much the user has visited the page before). It's common when testing this code to see a popup blocker the first time the new feature is used and then not see it again.

This scheme will not work from a file:// based URL due to browser security restrictions for file:// URLs.

The source website must not be served with the Cross-Origin-Opener-Policy: same-origin header. For example, see this issue.

Where does the posted trace go?

The Perfetto UI is client-only and doesn't require any server-side interaction. Traces pushed via postMessage() are kept only in the browser memory/cache and are not sent to any server.

Customizing the UI with URL parameters

Beyond just opening a trace, you can control the initial UI state using URL fragment parameters. These work with both Option 1 (direct URL) and Option 2 (postMessage).

Zooming into a region of the trace

Pass visStart and visEnd to control the initial viewport. These values are raw timestamps in nanoseconds as seen in the SQL tables:

https://ui.perfetto.dev/#!/?visStart=261191575272856&visEnd=261191675272856

This opens the trace at ~261192s with a 100ms wide viewing window.

Selecting a slice on load

Pass ts, dur, pid, and/or tid parameters. The UI will query the slice table and find a slice matching the parameters. If found, the slice is highlighted. You don't have to provide all parameters; usually ts and dur suffice to uniquely identify a slice.

NOTE: We deliberately do NOT support linking by slice ID because slice IDs are not stable across Perfetto versions. Instead, link by passing the exact start timestamp and duration (ts and dur) as seen by issuing a query like SELECT ts, dur FROM slices WHERE id=....

Issuing a query on load

Pass the query in the query parameter.

Examples

Try these examples:

Remember to URL-encode strings where needed.

Startup commands

You can also automatically configure the UI itself when a trace opens by embedding startup commands in the URL. This is useful for dashboard integration where you want to provide users with a pre-configured analysis environment.

Pass startup commands in the startupCommands parameter as a URL-encoded JSON array. The commands execute automatically after the trace loads, allowing you to pin tracks, create debug tracks, or run any other UI automation.

// Example: Pin CPU tracks and create a debug track const commands = [ {id: 'dev.perfetto.PinTracksByRegex', args: ['.*CPU [0-3].*']}, { id: 'dev.perfetto.AddDebugSliceTrack', args: [ "SELECT ts, dur as value FROM slice WHERE name LIKE '%render%'", 'Render Operations', ], }, ]; const url = `https://ui.perfetto.dev/#!/?startupCommands=${encodeURIComponent( JSON.stringify(commands), )}`;

The startup commands use the same JSON format as described in the UI automation documentation, but must be URL-encoded when passed as a parameter. For the list of stable commands with backwards compatibility guarantees, see the Commands Automation Reference.

Source links

The source code that deals with the postMessage() in the Perfetto UI is post_message_handler.ts.