複数のアプリやMCPホストからブランド画像・動画を生成、調整、書き出し、挿入する作業を支援します。ライブラリ選択や修正依頼も扱います。
- スライド用のブランド画像を作りたいとき
- 既存素材をフィードバックに合わせて直したいとき
- 動画素材を生成して書き出したいとき
Analyticsのセッション録画を調べ、再生や取り込み、保存に関する問題を追跡します。録画内のエラーや操作の停滞を確認し、原因調査に役立てます。
Inspect, troubleshoot, and extend Analytics session replay recordings.
実行スコア 未検証
インストール方法を見るAnalyticsテンプレートのセッション録画を調査し、取り込み、保存、再生に関する問題を追うためのスキルです。録画の一覧や要約、イベントを対応するツールから確認し、ブラウザー上で起きたコンソールエラーやネットワーク通信、操作の停滞を調べます。録画にひもづくエラーや、遅いリクエスト、生成した成果物が使われたかどうかなども、利用可能な範囲で確認できます。録画データへのアクセスは権限に沿って扱い、外部エージェントに共有する際は録画単位の期限付きリンクを使います。
画面録画が再生できない、利用者がどこでつまずいたか知りたい、エラーや通信の失敗を録画と照らして調べたい場合に向いています。Analyticsアプリのセッション機能を保守する開発者や、サポート時の状況確認にも役立ちます。
対象はAnalyticsテンプレートのセッション録画です。実データを読むには適切なアクセス権が必要です。ローカル環境から本番の暗号化済み録画を読む場合は、対応する ANALYTICS_SECRETS_ENCRYPTION_KEY が必要です。資料は途中までのため、後半の仕様は反映していません。
この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Use this skill when working on /sessions, replay ingest, replay storage, or
agent answers about browser recordings in the Analytics template.
session_recordings and session_replay_chunks.list-session-recordings,
get-session-replay-summary, and get-session-replay-events./sessions/:recordingId is keyed by session_recordings.id, not
analytics_events.session_id.analytics_events.
Events can be linked beside a recording through session_id, but they are not
playable replay rows by themselves.session_replay_chunks rows to the
browser or agent.session-recording access before reading private blob refs.query-agent-native-analytics, dashboard panels) reads
session_recordings through the same session-recording access rule as
the UI: the caller's own recordings, plus recordings in the active org that
are org-visible or shared with the caller or that org. Any new SQL path over
recordings must use that rule, not an org_id match.ANALYTICS_SECRETS_ENCRYPTION_KEY in
an untracked local env file; do not replace the workspace-wide
BETTER_AUTH_SECRET just to read production replay storage.create-session-replay-agent-link. It mints a two-hour agent_access URL
scoped to the recording, embeds a small SSR discovery payload on
/sessions/:recordingId, and advertises
/api/session-replay/agent-context.json plus bounded
/api/session-replay/agent-events.json and
/api/session-replay/agent-diagnostics.json reads.session-replay.ts in
@agent-native/core) patches console (log/info/warn/error/debug),
window error / unhandledrejection, fetch, and XHR, and emits rrweb
custom events tagged agent-native.console and agent-native.network.console / network options on the session replay config; each
accepts a boolean or an options object ({ maxEvents?: number }); network
also accepts captureErrorBodies (default true) and maxErrorBodyLength
(default 2048) to control the bounded 5xx response-body snippet.maxErrorBodyLength chars; non-5xx and
network-failure (status 0) responses never carry a body. URLs are scrubbed,
messages are truncated, and recorder self-traffic (the replay ingest and
tracking endpoints) is excluded.deriveReplaySignals computes the real errorCount from tagged
console events plus the additive networkErrorCount column on
session_recordings. Keep new columns additive.trackEvent also emits an agent-native.event custom event holding only
{ name } (120 chars max, 1000 per replay, counted across page reloads).
Telemetry names such as pageview, action.response, and session status
stay unmarked; lifecycle aliases don't get a second marker. Never add event
properties to the payload./_agent-native/actions/<name> requests as "Action failed", only while the
Sessions triage Lab is on. With the Lab off the viewer and the agent timeline
keep their earlier shape.recordAnalyticsEvents writes the per-session event index
(analytics_session_events) and a per-tenant coverage start inside the
transaction that stores the events, in every sink mode. After that
transaction commits it writes the daily catalog
(analytics_event_catalog_daily) and each event's latest sighting
(analytics_event_catalog_latest) best-effort, together in one short
transaction, because the catalog lists events from the latest table. A
catalog failure only warns, and the catalog never decides a filter. Lists,
did/didn't filters, and the catalog read only these tables, never BigQuery.
The catalog keeps the 1,000 most recently seen events, sorted by volume, and
sets truncated when it cut the list; its app flags still count every event
in the range.server/lib/indexed-text.ts (event name, app, template, path) before any
table sees it. A long user key keeps a prefix plus a hash of the whole value
(boundedIdentity), so two users never merge into one. Row ids built from
caller text go through indexedRowId, which hashes an id that
percent-encoding made too long. Session and recording ids are never cut,
because a cut id could merge two sessions: replay ingest rejects session and
recording ids over 256 characters, and an event's longer session id skips the
session index. Bound any new indexed caller value there./track, /api/analytics/replay) returns a thrown message
only for an error built with requestError (a numeric statusCode). Any
other failure is logged and answered with a generic 500, because its message
can quote internal database details.analytics_session_event_gaps in the same transaction, so a later
successful batch cannot make them look complete. If the marker cannot be
written either, the batch fails and its events are not stored. Keep session
index writes inside that transaction. Deploys ship code before the scheduled
migration creates these tables, so until analytics_session_event_coverage
exists ingest stores events unindexed and warns: with no coverage, no
session can read as complete. Reads in that window report no coverage
instead of failing: no event names, a null coverage start, an empty
catalog, and no session matching an event filter. That is the only unmarked
gap, and it holds only while the coverage table is the last index table a
migration creates.
The retention sweep removes a session's index rows together, once all of
them are two days past replay retention, and its gap marker after that. The
BigQuery-cutover purge leaves these tables alone.STALLED_REQUEST_THRESHOLD_MS, 4xx and 5xx responses) come from the
rrweb chunks in recordSessionReplayChunks, one row per recording in
session_recording_friction. Event signals (failed actions, agent
failures, stuck chats, thumbs-down, quick backs, cancelled runs) and their
trouble groups come from tracked events in a savepoint nested inside the
event index savepoint, one row per session in analytics_session_friction
plus analytics_session_trouble.isBenignAbort
in core recognizes, or the recorder's XMLHttpRequest aborted) is not a
failure: it never feeds retry loops or leaving after an error. Neither is
one the recorder marked pageLeaving: the browser cancels in-flight
requests when the page navigates or reloads, with the same "Failed to
fetch" as a network failure, so only the recorder can tell them apart. It
still counts as a stalled request. Any other status-0 failure counts.page_load_id on each pageview). Pageviews from older
clients send no id and are skipped: followed together, two tabs would look
like one tab going back.processed_chunks equals the recording's
chunk_count. Each batch continues from the stored detector state, whose
lastSeq is the highest chunk measured; a seq the recorder lost is skipped.
A batch that cannot be measured, or a chunk below lastSeq, leaves the row
behind and the recording reads as unmeasured until it ends. Then
remeasureReplayFriction measures every stored chunk again in seq order;
never continue a row that fell behind from fresh state. An event row
counts only when the tenant's friction coverage began before every
recording of the session and the session has neither an event index gap
nor a friction gap (analytics_session_friction_gaps). A friction write
failure rolls back only friction and records a friction gap; the index
write stays. Only a failed friction gap insert fails the index savepoint.agent_signals
(AGENT_SIGNALS_PAGEVIEW_PROPERTY in core): older clients sampled stops,
sent no ratings, and sent no page_load_id. One session id
spans every tab, so an old tab can share a session with a new one: any
unmarked pageview or sampled stop sets agent_signals_missing, and both
flags are OR-merged. Unless agent_signals_measured is set and
agent_signals_missing is not, these counts read as null, stay out of the
score, never match a filter, and sort last. A stop counts only when sent
unsampled (sample_rate absent or 1).analytics_session_friction_coverage (created
last), ingest skips friction, filters match nothing, friction sorts fall
back to newest, and details report every part as null. A friction filter or
sort always returns the paginated shape with frictionCoverageStartedAt,
and view-screen passes it on, so an empty match is read against coverage,
never as zero. It covers the viewer's own org and personal tenants: the
latest start among those with coverage, or null when one without coverage
has recordings the viewer sees in the range. Recordings shared from other
tenants read unmeasured on their own rows.errorIssues links occurrences in error_events, which keeps only each
issue's newest ones, then falls back to issues whose
last_session_recording_id is the recording, with a null count. A
recording with errors Monitoring could capture and still no issue reads
null (unknown), never [], unless its owner scope has no issues at all: it
does not capture errors as issues, so [] is the truth there. Only captured
exceptions can become issues, and a plain console.error never does: the
recorder marks console errors exception: false or true, and the replay
row counts the others in issue_errors, so a recording whose only errors
were plain console errors reads []. A row measured before that column, or
not measured from its start, falls back to the recording's errorCount.AGENT_TROUBLE_CAUSES in core
(no_model_connected, rate_limit, context_overflow, provider_error),
else by error code, never by message text. Failed actions group by action
and status.
New causes need product approval; add them to that one list.SESSION_FRICTION_SIGNAL_CAP, computed per part at ingest and summed at
read. Change weights only in SESSION_FRICTION_WEIGHTS.list-session-recordings, list-session-friction, view-screen, and
get-session-replay-summary; a 403 names what the Lab gates
(assertSessionsTriageLabEnabled takes every feature the request used).
With the Lab off, Sessions looks and behaves exactly as before; ingest
still records friction. Waiting on the Lab state is shared with the speed
filter; see "Performance In Sessions".list-session-friction, one page of ids at most,
through the recordings' access filter. A failed friction read then leaves
the list in place with a retry. With a friction filter or sort, friction
comes with the list and a failure is a list error.get-session-replay-summary returns
the same friction for the agent. A failed Lab state or friction read is
reported as labStateError or frictionError, never as no friction. Each
is a fixed message, because the cause can quote database details; the
server log keeps it. On
the list, view-screen reports them beside the base list, and its
activeFilters echo the filters it applied, not the URL's. Its row excerpt
drops trailing rows to stay under the agent's 50,000-character tool-result
limit, so the page metadata after the rows always arrives; a cut sets
truncated, and fullPageAction reads the whole page. Keep it that way
when adding per-row fields: a bigger row means fewer rows, not a lost page.web_vitals event per page view (route,
navigation_type, and whichever of ttfb_ms, lcp_ms, inp_ms, cls were
measured; an unmeasured metric is absent, never 0) and an
agent-native.vitals replay marker with the same numbers. action.response
carries the route its request started on. route is a React Router
template such as /sessions/:id; when no manifest route matches it is
omitted, never a raw path, which can hold slugs and emails.SLOW_REQUEST_THRESHOLD_MS (shared/slow-request.ts, 1 s)
are sampled at 10% with sample_weight: 10; slow, failed, and 4xx responses
always send with weight 1, so slow-request counts are exact. Use that
constant for every "slow request" rule. Requests made while the page was
hidden or cancelled are not counted. Slow requests (the app's own actions,
1 s, counted from events) are not friction's stalled requests (any captured
replay request, STALLED_REQUEST_THRESHOLD_MS, 3 s): keep their names,
fields, columns, and copy apart, and never show one number under the
other's label.route, app, and the
session id before hashing, as Postgres would store them; otherwise two
values that store alike collide in one upsert and fail the batch.
Measurements above performanceCeiling (the open top bucket's floor: 64 s,
CLS 5) are capped there rather than dropped, and sample_weight at 10,000.
A session value at the ceiling is a floor: summaries list it in atLeast
and the row hint shows it with ≥.recordSessionPerformance keeps each session's worst vitals and its slow
requests in analytics_session_performance, inside the ingest transaction
under a savepoint, with the same gap and coverage rules as the event index.
recordRoutePerformance adds weights to fixed histogram buckets in
analytics_route_performance_daily after commit, in its own short
transaction. A failed write records a gap: session_id = '' marks a
route day, read as incompleteDates; a session id marks that session,
read as performance.incomplete and kept by slow: any only, since
missing data cannot rule it out; vitals and requests need a measured
slow value. The slow filter correlates on each recording's own tenant. As
with event friction, a share grants the recording, not its tenant's
events: a recording shared from another tenant has no speed summary (null)
and never matches a slow filter. A summary's slowRequests is null when the session made no
measured request. A null summary is a session never measured: its row says
"Speed not measured", and a slow match or a range from before coverage
shows when speed coverage began, so it never reads as fast. On
list-session-recordings, slow and includePerformance always return
the paginated shape with performanceCoverageStartedAt, as friction does.
Bucket edges are positional, so changing them needs a new
PERFORMANCE_HISTOGRAM_VERSION.atLeast.
A metric with no samples is null: no data, never fast. Before the migration
creates analytics_performance_coverage, ingest stores events without these
aggregates and warns, the slow filter matches nothing, and reads report no
coverage.agent-native.slow_request
events core records beside each slow action.response someone waited for,
with that event's own duration, status, and outcome. Core and the timeline
both apply the count's rule (isWaitedActionResponse, from core), so a
marker matches exactly what the row counts and background requests never
spend the replay's marker budget. Never derive them from replay network events: those stop timing at
the response headers. Replays from clients without these events show no
slow-request markers.slow and includePerformance on list-session-recordings,
list-session-performance, list-route-performance, the replay's vitals
and slow-request markers, and performance on get-session-replay-summary
exist only while the Sessions triage Lab is on.slow, unused), with one wait for all of them, and for at most 5 s; a
failed or hung read lists sessions without them and says so once, with a
retry, rather than telling the user to turn on a Lab that may be on.
Row speed hints load beside the list through list-session-performance,
like row friction, keyed on the visible recording ids; when they fail the
page says speed data could not load instead of showing no hints, apart
from any friction failure. view-screen reads Lab state in its own try
and reads row friction and speed hints beside the base list, reporting
labStateError, frictionError, and performanceError separately; its
fullPageAction asks for both.OUTPUT_USE_RULES in shared/output-use.ts is the one definition: per
app, the output type, the events that make one, and the events that use it,
each with a qualifies check on its properties. A use counts only for the
same output_id the making event carried, within OUTPUT_USE_WINDOW_DAYS
(7). Opening an output never counts; a use shows it to people or takes it out
of the app. Slides: generation_completed makes a deck;
presentation_ended with slides_advanced ≥ 1 and duration_ms ≥
MIN_PRESENTATION_MS (30 s), or deck_exported with status: "completed"
and slide_count ≥ 1, uses it. A missing or non-numeric property never
proves a use.output_id. Until then the event catalog flags it: an
app with makesOutputs (it sent generation_completed) and empty
usedItEvents is a gap, and entries carry outputRole. Known holes:
shared-audience presentations carry no output_id, and HTML export has no
completion event.recordOutputOutcomes runs in the ingest transaction under a savepoint in
every sink mode, so views never read raw events or BigQuery. Each
analytics_output_outcomes row keeps the earliest making, its session, and
the earliest qualifying use; the upsert merges batches in any order. A failed
outcome write records the batch's event-time span per tenant in
analytics_output_outcome_gaps, and so does recordLostOutputBatch when
ingest fails to store a batch at all (sink lookup, volume limit, raw insert,
index), since
the tracker does not resend it. An output whose window overlaps a gap is
unmeasured, never unused, since the lost batch could hold its use.
Outputs made before the tenant's coverage start are skipped. Before the
migration creates analytics_output_outcome_coverage (created last), ingest
stores events without outcomes, unused matches nothing, and coverage is
null.unused on list-session-recordings matches recordings whose own
tenant's session made an output whose window has closed unused; a recording
shared from another tenant never matches, nor does one a gap overlaps (a
lost batch may have held an output it made). It returns the paginated shape
with outputs and omittedOutputs by recording id and
outputCoverageStartedAt. Statuses are used, unused, open (window
still open), and unmeasured; url is the recording's origin, its
/<app> workspace mount when its first or last page is under it, and the
rule's outputPath. Recorded URLs come from the uploader, so url is null
unless the recording's replay key lists that origin (a key that accepts any
origin links nothing) and both pages share it (a real recording never
leaves its tab's origin). The app checks access when it opens.getSessionRecordingOutputs is the one reader. Per readable recording it
gives [] for none, null when they are unknown (a recording from another
tenant, since a share grants the recording, not its events, one whose
tenant has not started output tracking, or one a gap overlaps), and at most MAX_OUTPUTS_PER_RECORDING
outputs, ranked unused first in SQL so a matched row always lists what it
matched on; omittedOutputs counts the rest. Ids the viewer cannot read are
absent. list-session-outputs returns that shape and rejects a failed read.
get-session-replay-summary and view-screen on a replay both use
withSessionsTriage, which puts one recording's outputs (and
omittedOutputs when some were left out) beside its friction and speed, and
returns outputsError instead when the read fails or skips the recording.outputs in its 403). Rows
link the first unused output beside the replay link, never inside it, and
the replay header lists the recording's outputs with their status and says
how many more it left out.buildSessionReplayAgentContext includes a diagnostics section: up to 50
console entries and 50 network entries, errors/failures first, with totals
and truncated flags. Agent-context instructions steer agents to diagnostics
as the primary debugging signal.console-error / network-error markers; error
markers are kept preferentially under the 200-marker cap. App event, Web
Vitals and slow-request markers belong to the Sessions triage Lab and stay
off it (SESSIONS_TRIAGE_MARKER_TAGS); add any new Lab marker tag there.apis.diagnostics advertises the fuller bounded list:
GET /api/session-replay/agent-diagnostics.json?id=<recordingId>&agent_access=<token>&kind=console|network|all&level=<level>&limit=<n>&offset=<n>&fromMs=<n>&toMs=<n>
(limit defaults to 200, max 500). It uses the same recording-scoped
agent_access token as the other agent JSON APIs.offset and fromMs/toMs (inclusive offsetMs window) enable full
enumeration of a session's captured entries: page with offset, or window
with fromMs/toMs around a timeline marker's offsetMs. Providing any of
these switches ordering to strictly chronological (no errors-first
reshuffle) so pages are stable and disjoint. total/errorCount/
warnCount/failedCount reflect the filtered (windowed/level/kind)
population, not just the returned page, and each kind's response includes
hasMore alongside truncated so an agent can tell whether more entries
remain. Route validation rejects negative/non-numeric offset/fromMs/
toMs and fromMs > toMs with 400./sessions/:recordingId replay player has a Dev Tools toggle that opens
a panel with Console and Network tabs: filter chips, search, an error-count
badge, and playback-time highlighting.Replayer with liveMode: true and keep
that instance for the recording. Append later chunks with addEvent; never
rebuild the player as batches arrive, because that desynchronizes scrubbing
and the playhead. Do not call startLive(): retain rrweb's normal play/pause
state machine. Use the recording summary for the full duration while chunks
are still loading.Replayer untouched. rrweb rebuilds them in a sandboxed
iframe; pre-processing DOM, stylesheet, resource, or mutation payloads makes
playback diverge from the captured page. In particular, never rewrite href, src,
_cssText, CSS url(), or Meta URLs to about:blank; that exact remediation
broke historical replay CSS in PR #2040. Handle request privacy at capture or
the sandbox boundary instead of mutating stored rrweb events. Historical
captures without inlined resources require live stylesheet/image/font
requests for accurate rendering; the viewer accepts that fidelity tradeoff,
uses rrweb's script-disabled sandbox plus referrerpolicy="no-referrer", and
must never add credentials or proxy those URLs through a privileged server.src, srcset, poster, data, and href only on resource links such as
stylesheets, preloads, and icons. Signed CDN query parameters are part of the
resource identity; redacting them produces missing CSS, fonts, images, and
oversized fallback icons. Keep scrubbing Meta/navigation URLs, anchor hrefs,
and console/network diagnostics. Captured _cssText and CSS @import/url()
values must remain byte-identical.about:srcdoc iframe, which inherits the Analytics
document's CSP. Analytics currently sends no CSP header; if a future change
adds restrictive style-src, font-src, or img-src directives, verify
historical replays and resolve external imports/fonts at capture before
blocking the recorded resource origins. Do not diagnose current font loss as
CSP without checking the deployed response headers first._cssText and SVG attributes before rrweb ever saw the payload (heights
below 1000 stayed real, which is why the symptom looked like a viewport
problem rather than a redaction bug — two different sessions that both
stored a 1,152px width read back as the same 4,491px, a deterministic
salted-hash fingerprint of the redactor, not two coincidentally identical
malformed recordings). This is fixed in
packages/core/src/demo/fetch-interceptor.ts: raw replay payload and
manifest URLs are skipped from demo number redaction entirely, and must
never be routed through it again. Do not reintroduce viewport clamping or
pointer-coordinate projection in the player — they can now only corrupt
genuine future recordings (for example, a real 3440x900 ultrawide browser
window, or a short vertical window under 1,000px tall).triggerFocus makes a valid
snapshot diverge from the source page.insertStyleRules may suppress known toast/snackbar containers only. Never
hide generic framework primitives such as
[data-radix-popper-content-wrapper]: Radix dropdowns, selects, tooltips,
and other real recorded product UI all share that wrapper.SessionDetailPage.spec.ts — raw event identity, raw viewport dimensions,
and raw resize-state derivation (including the 3,189x885 tripwire against
reintroducing a clamp) — as regression guards against reintroducing any
viewport "recovery" or pointer-projection heuristic. Do not change their
expectations merely to bless a new sanitizer or clamp; validate the affected
replay in a browser first. An interim clamp for the exact 3,189x885 pair was
also deleted once the view-time redaction root cause was proven; the earlier
3,000-3,999px band was rejected because it also catches real 3440px-wide
displays. Neither the exact exception nor the band belongs in the player./sessions to find their recordings./sessions/:recordingId and click
Copy for agent to mint the two-hour tokenized link./api/session-replay/agent-context.json, reads the diagnostics section
and timeline markers first, then drills into apis.diagnostics (filtered
by kind/level) and apis.events for the fuller bounded lists as needed.VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY or configureTracking({ key }) is
present. The default sample rate is 100% of eligible sessions.configureTracking({ key, endpoint, sessionReplay: { enabled: true } }).configureTracking({ sessionReplay: false }).configureTracking() in their roots;
hosted template deployments only need the normal Agent-Native Analytics
Vite/Netlify env vars on the recorded site..an-mask or data-an-mask.SESSION_REPLAY_MASK_PROPS from @agent-native/core/client/session-replay-privacy on
the message element, including expanded details and failed tool rows. Keep
headlines and recovery controls outside the mask. The data-an-mask marker
remains active when an app supplies its own maskTextSelector; selectors
extend this privacy baseline. Do not rely on name redaction for run errors.
Masking covers text only; the recorder keeps attributes, so leave title off
masked failure text. Wrap failed content that can render links or embedded
frames, such as an MCP App or a failed activity summary, in
SESSION_REPLAY_BLOCK_PROPS..an-block, .an-ignore, data-an-block, or data-an-ignore for
sensitive zones that should not be captured.409 abandons only the conflicted replay identity and
immediately starts rrweb again under a fresh per-tab id, producing a new
Meta + FullSnapshot for long-lived SPA tabs. Recovery is limited to one
restart until an upload succeeds so a misconfigured endpoint cannot loop;
Analytics tracks the content-free session replay upload rejected lifecycle
event so conflicts and recovery success are measurable.まだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
複数のアプリやMCPホストからブランド画像・動画を生成、調整、書き出し、挿入する作業を支援します。ライブラリ選択や修正依頼も扱います。
特定の顧客企業について、契約と製品利用の数値を照らし合わせ、根拠や不足情報を明記した健全性レポートをまとめます。
アプリの操作をエージェントと画面の両方から呼び出せるアクションとして実装し、API連携や画面のデータ取得を一貫した形で追加するスキルです。
新機能をUI・エージェント用アクション・説明資料・画面状態の4領域でそろえ、利用者とエージェントのどちらからも一貫して使えるようにするチェックリストです。
複数のデータソースを照合して、傾向や指標、根拠をまとめた分析結果を作成します。必要に応じて、再実行できるダッシュボードとして保存できます。
Analyticsの管理画面で、機能フラグの状態確認と切り替え、ダッシュボード利用状況の調査、接続先アプリのデータベース管理を行います。