Get desktop application:
View/edit binary Protocol Buffers messages
Guidebook operations
Service definition
Source operations
Source registration for Resumable Upload (rpc.go:31) Request shape, captured from api.Client.registerFileSource (internal/notebooklm/api/client.go:952): [[[filename]], project_id, [2], [1, null × 9, [1]]] The arg_format directive cannot express the deeply-nested wrapper; a custom encoder lives at api.Client.registerFileSource. Returns the server-assigned source_id at response position [0][0][0].
AddFileSource (o4cbdc): register an uploaded file as a notebook source. HAR-verified across two pdf-upload captures (2026-04-19, pdf-upload/, pdf-upload-new/) — both byte-identical for the trailing options blob. Wire request: [[[filename]], project_id, [2], [1, null × 9, [1]]] Position [0] is a 2-level-nested filename list (the inner [filename] is a 1-element list). Position [2] is [2] = source_type=file_upload. Position [3] is the same fixed options blob seen in DeleteArtifact's V5N4be call. See api.Client.registerFileSource (client.go:952).
Wire response (HAR-verified): [[[[source_id], filename, [null, null, null, null, 0]]], null, [[[[source_id], filename, [null, null, null, null, 0]]]]] Positions [0] and [2] both echo the assigned source row; [1] is always null in the captured calls. The inner metadata list at position [2] of each row is [null × 4, status_int=0]. We surface the source_id only.
Update existing request messages to match Gemini's findings
BulkImportFromResearch (rpc.go:73). 5-position polymorphic variant of LBwxtb that imports a batch of URL+title pairs from a research session. HAR-verified 2026-04-17 against notebook 00000000-0000-4000-8000-000000000006, conversation 00000000-0000-4000-8000-000000000401, ten URL sources. Request shape (api.bulkImportArgs at client.go:5102): [null, [1], conversation_id, project_id, [source_1, ..., source_N]] Each source tuple is 11-position; encoded by Go helper because arg_format cannot represent the inner [null, null, [url, title], null × 7, 2] tuple shape.
BulkImportFromResearch (LBwxtb, 5-position polymorphic variant). Wire shape: [null, [1], conversation_id, project_id, [source_1, ..., source_N]] HAR captures show two distinct per-source tuple shapes selected by position [10]: URL import (api.bulkImportArgs at client.go:5102, source_type=2): [null, null, [url, title], null × 7, 2] Note/text import (HAR-observed in NotebookLM web UI capture, 2026-04-23, importing a 3.4kB markdown research report, source_type=3): [null, [title, content_markdown], null, 3, null × 5, 3] The Go side currently encodes only the URL variant; the note variant is a follow-up. BulkImportSourceInput carries enough fields to model both — content stays empty for URL imports, url stays empty for note imports.
BulkImportFromResearchResponse — per-source enriched metadata in request order. HAR shows a wide layout; we surface the durable subset (id, title, url) and leave the rest to future callers.
CancelDiscoverSourcesJob (Zbrupe). Cancels an in-flight DiscoverSources / DiscoverSourcesAsync / DiscoverSourcesManifold job. JS-bundle-verified; no HAR yet. TODO(har): trigger by canceling a running fast-research / deep-research / discover-sources flow before completion.
CancelDiscoverSourcesJob (Zbrupe).
CopyProject (te3DCe). Duplicates an existing notebook (sources, artifacts, settings) into a new project. JS-bundle-verified; no HAR. TODO(har): trigger from the "Make a copy" notebook menu.
CopyProject (te3DCe). Duplicates a notebook.
Artifact operations
Audio operations
e.g. "en"
CreateAudioOverview (AHyHrd). The legacy audio-overview creator. The production surface now goes through CreateUniversalArtifact (R7cb6c with kind=2), but a direct AHyHrd path is still wired in api.Client.createAudioOverviewDirectRPC (client.go:1407) as a fallback. JS-bundle-verified; HAR-observed under that fallback.
CreateAudioOverviewLegacy (AHyHrd). Direct-RPC fallback that api.Client.createAudioOverviewDirectRPC still uses; the live UI now goes through R7cb6c. The "Legacy" suffix avoids a name collision with the modern CreateAudioOverview rpc that targets R7cb6c above.
CreateLabel / MutateLabel / DeleteLabels — write companions to GetLabels (I3xc3c). All three are bound by the JS bundle but no HAR has been captured yet; trigger by interacting with the labels affordance in the source-list UI.
Label write companions — wire shape unverified.
Note operations
Project operations
Request messages reconstructed from captured batchexecute traffic.
Video operations (uses same R7cb6c RPC as audio but with mode=3)
Video overview request (uses same R7cb6c RPC as audio, but with mode=3 parameter)
Content style (only BRIEF=2 observed so far)
Visual presentation style
e.g. "en"
Wire format: [null, null, %project_id%] Polymorphic endpoint shared with PollDeepResearch
DeleteDeepResearch (rpc.go:72). Soft-delete a research session; server transitions state 2 -> 5 (the row is retained, future poll queries skip state=5). HAR-verified 2026-04-17. Polymorphic with BulkImportFromResearch: same LBwxtb id, server discriminates on arg-4 presence (delete = 4-position, bulk-import = 5-position). Request shape (api.deleteDeepResearchArgs at client.go:5034): [null, [1], conversation_id, project_id]
DeleteDeepResearch (LBwxtb, 4-position polymorphic variant). Wire shape: [null, [1], conversation_id, project_id]
empty array on success
(message has no fields)
DiscoverSources (Es3dTe). Per the JS bundle binding to /LabsTailwindOrchestrationService.DiscoverSources. The previous rpc_id "qXyaNe" was a speculative inference that does not match any JS bundle entry or HAR capture; corrected to Es3dTe. No HAR yet for the wire shape. arg_format below is a likely shape based on sibling RPCs but is unverified — TODO(har): capture by triggering "Discover sources" from the source-add UI. Note: the related research-flow RPCs (Ljjv0c, QA9ei, e3bVqc, LBwxtb) are bound by the JS bundle to DiscoverSources*-family names (DiscoverSourcesManifold, DiscoverSourcesAsync, ListDiscoverSourcesJob, FinishDiscoverSourcesRun); the "research" feature is layered on top of the DiscoverSources job system.
ExecuteWritingFunction (likKIe). In-document writing assistant — rewrite, expand, summarize a selection inside an artifact. JS-bundle-verified; no HAR. TODO(har): trigger from the artifact editor's writing toolbar.
ExecuteWritingFunction (likKIe). In-document writing assistant.
e.g. "rewrite", "expand", "summarize"
ExportToDrive (Krh3pd). Pushes notebook artifacts to the user's Drive. JS-bundle-verified; no HAR yet. TODO(har): trigger by clicking "Export to Drive" on a notebook.
ExportToDrive (Krh3pd). wire shape unverified.
FetchInteractivityToken (rpc.go:50). Voice-session auth + ICE server config for the WebRTC interactive-audio mode. Request is the empty payload []. Response is a positional JSON envelope whose [0] field is a JSON-encoded string carrying {lifetimeDuration, iceServers, blockStatus, iceTransportPolicy}. See internal/interactiveaudio/signaling.go:36 and the existing FetchInteractivityTokenRequest/Response messages at line 858+.
FetchInteractivityToken (Of0kDd). HAR-verified (docs/captures/notebooklm.google.com.jsonl:24, 2026-04-06). Request is the empty payload []. Response is a 1-element JSON array whose [0] entry is a JSON-encoded string carrying the WebRTC bootstrap blob: lifetimeDuration, iceServers (STUN+TURN credentials), blockStatus, and iceTransportPolicy. Decoded by interactiveaudio.parseInteractivityTokenResponse (signaling.go:72) which JSON-unmarshals the inner string into a Go-side InteractivityToken struct that mirrors these fields.
Wire format: [] (empty payload)
(message has no fields)
e.g. "86400s"
e.g. "NOT_BLOCKED"
e.g. "all"
GenerateAccessToken (preRPe). Per-session token mint — likely used by embed widgets or third-party surfaces that need a short-lived credential. JS-bundle-verified; no HAR.
GenerateAccessToken (preRPe). Per-session token mint.
GenerateArtifact (Rytqqe). Distinct from CreateArtifact (xpWGLf) and CreateUniversalArtifact (R7cb6c). Likely the trigger that takes a SUGGESTED-state artifact (see ArtifactState.SUGGESTED) and promotes it to a generated one. JS-bundle-verified; no HAR yet. TODO(har): trigger by clicking a suggested-artifact card.
GenerateArtifact (Rytqqe) — distinct from CreateArtifact (xpWGLf) and CreateUniversalArtifact (R7cb6c). Likely promotes a SUGGESTED artifact to a generated one. wire shape unverified.
GenerateArtifactSuggestions / AudioTopicSuggestions (rpc.go:133). The web UI calls this before R7cb6c (CreateUniversalArtifact) to get a list of AI-generated topic blueprints. Wire format verified against HAR (create-audio, 2026-04-14): [[kind], project_id, [[src1], [src2], ...], variation] Only audio (kind=2) is HAR-verified; video and slide kinds are not covered. The variation int re-rolls suggestions (1, 2, 5, 6 observed). See internal/method/labs_tailwind_artifact_suggestions.go.
GenerateArtifactSuggestions / AudioTopicSuggestions (otmP3b). HAR-verified for kind=2 (audio) via the create-audio capture used for internal/method/labs_tailwind_artifact_suggestions.go (filed 2026-04-14; not present in this repo's docs/captures/ but the encoder is the durable record). Wire request: [[kind], project_id, [[src1], [src2], ...], variation] Wire response: [[[title, description], [title, description], ...]] Each call returns three suggestion pairs. variation is a re-roll seed (1, 2, 5, 6 observed); the UI bumps it on every "refresh" click. Video and slide kinds are not yet HAR-verified.
2 = audio (HAR-verified); 3,4 speculative
re-roll seed
GenerateDocumentGuides (rpc.go:82). Per-source guide RPC: the wire call is keyed by source_id with a 4-level-nested arg shape [[[[source_id]]]] that the arg_format template cannot express. Invoked via api.Client.GenerateSourceGuide (client.go:3010); response is [[[null, [summary], [[topic, ...]], []]]]. The request message exists at line 709 (GenerateDocumentGuidesRequest).
Generation operations Per-source guide generation (tr032e) is not declared here; the wire call is keyed by source_id with a 4-level-nested arg shape that the [%project_id%]-style arg_format cannot express. It's invoked directly via rpc.Do in the api package (see api.Client.GenerateSourceGuide).
The gRPC-Web endpoint still expects a manually constructed JSON array, but this message mirrors the observed request state on that wire: [ [[[source_ids]]], prompt, history, [mode, null, citation_modes, follow_up_modes], conversation_id, draft_response_id, parent_response_id, notebook_id, sequence_number ]
chunk preserves the cumulative answer text used by existing callers.
is_final mirrors the completion flag at response position [4].
Type of guide to generate (2 = mind map)
GenerateReportSuggestions (ciyUvf). HAR-verified; see internal/method/LabsTailwindOrchestrationService_GenerateReportSuggestions_encoder.go. GHsKob is a legacy/predecessor id for the same logical RPC. It does not appear in the current JS bundle (boq_labs-tailwind-frontend) and has no observed wire traffic. Treat GHsKob as dead; ciyUvf is the live id.
GetArtifact (v9rmvd). The JS bundle binds v9rmvd to /LabsTailwindOrchestrationService.GetArtifact, so the RPC does exist on the wire — it just isn't invoked by the live web UI, which prefers gArtLc (ListArtifacts) + client-side filter for its rendering path. The earlier BnLyuf id was a different, unreachable inference that returned 400. No HAR evidence in the surveyed corpus (the UI never fires this ID). api.Client.GetArtifact still uses the gArtLc scan fallback; a future direct caller can target v9rmvd once a wire shape is captured. TODO(har): capture the request/response shape by hitting v9rmvd directly (e.g., from a custom JS console snippet) and refine GetArtifactRequest/Response.
GetArtifactRequest. The wire id is v9rmvd (per JS bundle binding to /LabsTailwindOrchestrationService.GetArtifact). The web UI never fires this RPC, preferring a gArtLc scan + filter, so the request shape is unverified by HAR. arg_format = "[%artifact_id%]" is the likely shape based on sibling artifact RPCs.
GetArtifactUserState (ulBSjf). Read companion to UpsertArtifactUserState (Fxmvse). Both are bound by the JS bundle to /LabsTailwindOrchestrationService.GetArtifactUserState. No standalone HAR observed: the read path is rolled into the gArtLc (ListArtifacts) response — each artifact tuple already carries the saved ArtifactUserState inline at a late field position (the same [[[seconds, nanos]]] shape that Fxmvse upserts). The dedicated ulBSjf read is reserved for hosts that need the per-artifact value without re-listing. TODO(har): capture a direct ulBSjf request to confirm the request body shape; the read response is expected to mirror UpsertArtifactUserStateResponse (a single ArtifactUserState).
GetArtifactUserState (ulBSjf). Read companion to UpsertArtifactUserState (Fxmvse). No HAR observed for the dedicated read path: the value is also returned inline by gArtLc (ListArtifacts) as part of each artifact tuple, and the UI reads it from there. The fields below mirror the HAR-verified write side; the request likely sends only the artifact_id, and the response is expected to wrap a single ArtifactUserState the same way as UpsertArtifactUserStateResponse. TODO(har): capture a standalone ulBSjf request to confirm.
GetAudioFormats (rpc.go:89). HAR-verified 2026-04-07 in docs/captures/notebooklm.google.com.jsonl. Request payload observed verbatim: [[2, null, null, [1, null × 9, [1]], [[1,4,2,3,6,5]]], null, 1] Returns the audio-overview style menu (Deep Dive, Brief, Critique, Debate). The opaque inner [1, null × 9, [1]] and ordering vector [[1,4,2,3,6,5]] are bytes captured verbatim; semantics not yet decoded.
GetAudioFormats (sqTeoe). HAR-verified against 11+ captures (notebooklm.google.com.jsonl, 2026-04-19..2026-04-23). Returns the full create-artifact menu — audio styles, video styles, slide styles, AND the prebuilt briefing-doc/study-guide templates. The request is a fixed-sentinel payload (no varying fields), so it has no arg_format. The same RPC powers every "create X" picker the UI shows.
Wire shape: [[2, null, null, [1, null × 9, [1]], [[1,4,2,3,6,5]]], null, 1] Custom encoder; no field substitution.
(message has no fields)
Response shape (HAR-verified): [ [<audio_kinds>], // [[id, name, description], ...] [<video_kinds>], [<slide_kinds>], [<doc_templates>], // [title, subtitle, system_prompt] ..., ] We surface only the audio kinds today (the existing api.Client.GetAudioFormats path); other inner arrays are accessible via the raw payload until dedicated parsers exist.
Conversation lifecycle
Wire format: [[], null, %project_id%, %limit%]
GetDeepResearchSessions (rpc.go:71). Polymorphic with DeleteChatHistory: same e3bVqc id, server discriminates on request payload shape. The deep/fast-session list call uses [null, null, project_id] (api.Client.pollResearch at client.go:4758). Returns ALL deep + fast sessions for the notebook; the caller scans by (research_id, mode=5) for deep or (conversation_id, mode=1) for fast.
GetDeepResearchSessions (e3bVqc, polymorphic with DeleteChatHistory). Wire shape: [null, null, project_id] Response is a list of deep+fast research sessions; clients filter by (research_id, mode=5) for deep or (conversation_id, mode=1) for fast.
GetLabels (I3xc3c). JS bundle binds this to /LabsTailwindOrchestrationService.GetLabels. HAR-verified across 8+ NotebookLM web UI captures (2026-04-23). Returns the notebook's labels (a.k.a. autolabel/source-grouping clusters): per-label tuples carrying a label, a member source list, and a server-assigned group UUID. Most notebooks return [] (no labels computed yet). Notebooks where the user has invoked autolabel return populated entries. Wire request: [[2], project_id] [0] = [2] is an opaque mode/operation enum (constant across all captures); semantics not yet decoded. Wire response: [] OR [[label, [[src_id], ...], group_uuid, ""], ...] Earlier rounds of this proto called this method GetSourceGroups — the canonical service name (per JS bundle) is GetLabels, and the related operations CreateLabel (agX4Bc), MutateLabel (le8sX), and DeleteLabels (GyzE7e) confirm the labels framing.
GetLabels (I3xc3c). HAR-verified label/autolabel query. The notebook UI fires this on every notebook load to render the source-list section headers; an empty response means the user hasn't yet computed labels for this notebook.
GetMagicView (rtY7md). Read companion to GenerateMagicView (uK8f7c). JS-bundle-verified; no HAR. TODO(har): trigger by opening a previously-generated Magic View.
GetMagicView (rtY7md). Read companion to GenerateMagicView (uK8f7c).
Account operations
Account management
Empty for now, uses auth token
(message has no fields)
Analytics and feedback
ListExpertIntelligenceContent (mVtEUb). Curated featured-content surface (the "Expert intelligence" gallery). JS-bundle-verified; no HAR. TODO(har): visit the featured/expert-content tab to capture.
ListExpertIntelligenceContent (mVtEUb). Curated featured surface.
(message has no fields)
ListModelOptions (EnujNd). Returns the menu of available chat / generation models for the signed-in account. JS-bundle-verified; no HAR yet. TODO(har): trigger by opening the model-picker in chat.
ListModelOptions (EnujNd). wire shape unverified.
LogEvent / GetPromoCampaign (rpc.go:98). The constant in rpc.go is labelled "LogEvent" but HAR evidence (notebooklm.google.com.jsonl hits across 12+ captures spanning 2026-04-19..2026-04-23) shows it is actually a promo/upsell-card placement lookup. The web UI fires it once per page load. Request shape: [[[[null, "1", 627], [null × 9, [null, null, 2]], 1]]] The middle-positional 627 looks like the campaign/promo slot ID; "1" is locale or surface; the [null, null, 2] tail is opaque. Response carries the upsell card payload (icon URL, title, CTA link, the user's tier — e.g. "NOTEBOOKLM_TIER_PRO_CONSUMER_USER"). The Go side does not call this RPC; it is documented here so the proto matches what the wire actually does.
LogEvent (ozz5Z) is a misnomer per rpc.go's constant; the wire RPC is actually a promo/upsell-card placement lookup. HAR-verified across 12+ captures (notebooklm.google.com.jsonl, 2026-04-19..2026-04-23). Wire request: [[[[null, "1", 627], [null × 9, [null, null, 2]], 1]]] 627 is the campaign/slot id (constant across all captures); "1" is locale/surface; the [null, null, 2] tail at position [9] of the inner array is opaque. The whole request is a fixed sentinel — the only varying byte is the f.sid, which lives outside the f.req body. No Go caller invokes this RPC today; the message exists so future regenerated stubs match the wire reality rather than the rpc.go label.
No fields: the request is a constant sentinel envelope.
(message has no fields)
Wire response carries the upsell card payload. Captured layout (heavily nested; only the surfaceable subset is decoded here): [[[ [null, "1", 627], [[1601, [null × 9, [[null, "NotebookLM icon", "edit"], [[[null, null, "<settings_url>"], false], null, null, "Manage subscription", null, "Manage subscription", null, null, [<dismissal_blob>]]]], null × 8, "NOTEBOOKLM_TIER_PRO_CONSUMER_USER", null, null, false]], 0]]] We surface the user-tier string (the only durable, human-meaningful field). All other content is rendering metadata.
Example value: "NOTEBOOKLM_TIER_PRO_CONSUMER_USER".
Conversation feedback (rpc.go:65) TODO(har): wire shape unverified — no rpcids=J7Gthc seen in any capture under NotebookLM web UI capture corpus or docs/captures/. To capture: (1) load a notebook with chat history, (2) click thumbs-up or thumbs-down on an assistant reply, (3) grab the resulting batchexecute POST. Until captured, do not call this RPC — the placeholder fields are speculative.
RateConversationTurn (J7Gthc): thumbs-up/down on a chat turn. TODO(har): no rpcids=J7Gthc seen in any current capture. To capture: (1) load a notebook with chat history, (2) click a thumbs-up or thumbs-down icon on an assistant reply. The fields below are speculative — do NOT call this RPC until the wire is captured.
speculative: 1=up, 2=down
wire shape unverified; capture HAR before encoding
(message has no fields)
Needed for source-path URL param
ReportContent. User-initiated abuse/safety report. The JS bundle binds the live ReportContent endpoint to OmVMXc; the historical rJKx8e id never surfaced in any HAR capture or in the bundle, so it is treated as stale (kept as RPCReportContentLegacy for compatibility, no proto entry). TODO(har): no rpcids=OmVMXc seen in any capture under the current web-UI corpus. To capture: open an artifact, click the kebab menu -> "Report", fill the dialog, submit. The placeholder fields are speculative.
ReportContent (rJKx8e): user-initiated abuse/safety report. wire shape unverified; capture HAR before encoding
wire shape unverified; capture HAR before encoding
wire shape unverified; capture HAR before encoding
(message has no fields)
ReviseArtifact (rpc.go:131). Re-runs an artifact generator with a free-form revision instruction. TODO(har): no rpcids=KmcKPe seen in any capture. To capture: open a generated artifact (audio overview, briefing doc, mind map), click "Revise" or the equivalent edit affordance, type an instruction, submit. The placeholder fields are speculative.
ReviseArtifact (KmcKPe): revise an artifact with instructions. wire shape unverified; capture HAR before encoding
wire shape unverified; capture HAR before encoding
wire shape unverified; capture HAR before encoding
SDPExchange (rpc.go:51). WebRTC SDP offer/answer exchange for the interactive-audio voice session. Request payload is a single string holding {"sdp": "...", "type": "offer"} JSON; the server returns the answer SDP wrapped the same way. See internal/interactiveaudio/signaling.go:52.
SDPExchange (eyWvXc): WebRTC SDP offer/answer exchange. HAR-verified (docs/captures/notebooklm.google.com.jsonl:25, 2026-04-06) — request args = [json_str] where json_str is `{"sdp":"...","type":"offer"}`. Response is `[json_str]` where json_str is the answer SDP wrapped the same way, with `"type":"answer"` and an active fingerprint. Encoded/decoded by interactiveaudio.exchangeSDP (signaling.go:52). The wire keeps the SDP as an opaque JSON-encoded string blob; this proto exposes the decoded sdp+type pair for callers that prefer structured access.
Raw JSON string sent on the wire — kept as a string because the server treats it opaquely and round-trips byte-for-byte.
StartDeepResearch (rpc.go:70). Wire shape verified across three independent CDP captures spanning 2026-04-10 through 2026-04-17 (api.Client.StartDeepResearch at client.go:4686). Request: [null, [1], [query, 1], 5, project_id] Response is a two-element array: [research_id, conversation_id].
StartDeepResearch (QA9ei): kick off a deep-research session. Wire shape verified across three independent CDP captures spanning 2026-04-10..2026-04-17 (api.Client.StartDeepResearch at client.go:4686). No HAR copy in this repo's capture set; the verification is the dedicated capture suite that gated this RPC from speculative to first-class. Wire request: [null, [1], [query, 1], 5, project_id] Wire response: [research_id, conversation_id] Position [3] = 5 distinguishes deep from fast (which uses 1 at the same position structurally, though shifted because the leading null + [1] are absent in fast). Both IDs are retained because different downstream RPCs key on different ones (poll uses research_id, delete uses conversation_id).
(message has no fields)
Research operations StartFastResearch — HAR-verified 2026-04-17 against notebook 00000000-0000-4000-8000-000000000006 (rpc.go:68). Request shape (api.startFastResearchArgs at client.go:4587): [[query, 1], null, 1, project_id] Response is a one-element array: [conversation_id]. Mode enum at position [2] is 1 for fast (5 for deep, see StartDeepResearch).
StartFastResearch (Ljjv0c): kick off a fast-research session. Wire shape verified by api.startFastResearchArgs (client.go:4587), against notebook 00000000-0000-4000-8000-000000000006, query "har harl file formats" (NotebookLM web UI capture, 2026-04-17). No HAR copy in this repo's capture set. JS bundle binding: Ljjv0c → DiscoverSourcesManifold. The "research" feature is built on top of the DiscoverSources job system; api.Client uses the StartFastResearch alias. Wire request: [[query, 1], null, 1, project_id] Wire response: [conversation_id] Mode int at position [2] is 1 for fast, 5 for deep. The trailing 1 at position [0][1] is opaque (same byte the deep variant carries).
(message has no fields)
UpdateFeaturedNotebookStatus (DemIHe). Admin/internal. Fired only by the featured-notebook curation surface. JS-bundle-verified; unlikely to ever be exercised by an end-user account.
UpdateFeaturedNotebookStatus (DemIHe). Admin-only.
UpdateProjectUserState (LQhfEb). Per-user notebook state — last-viewed-at, pinned, hidden, etc. JS-bundle-verified; no HAR. TODO(har): trigger by pinning/unpinning a notebook.
UpdateProjectUserState (LQhfEb). wire shape unverified.
UpsertArtifactUserState (Fxmvse). JS bundle binds this to /LabsTailwindOrchestrationService.UpsertArtifactUserState. The companion read RPC is GetArtifactUserState (ulBSjf). HAR-verified 2026-04-25 against NotebookLM web UI interactive-audio capture set (22 samples). The web UI fires this every ~5s during interactive audio-overview playback to persist the listener's playback position. The request body is [%context%, %artifact_id%, %state%] where state encodes a single PlaybackPosition (seconds + nanos) wrapped as [[[seconds, nanos]]] — see ArtifactUserState below.
UpsertArtifactUserState (Fxmvse). HAR-verified 2026-04-25 against NotebookLM web UI interactive-audio capture set (22 samples; web UI fires this every ~5s during interactive audio-overview playback to persist the listener's playback position). Wire request: [%context%, %artifact_id%, %state%] - context: standard project_context request envelope - artifact_id: UUID of the artifact (audio overview) - state: ArtifactUserState — encodes [[[seconds, nanos]]] The same ArtifactUserState value is also emitted inline in each gArtLc (ListArtifacts) artifact tuple at a late field position; that inline copy is what the UI reads on page load.
UpsertArtifactUserStateResponse echoes the persisted state. Wire response: [[[[seconds, nanos]]]] — a single ArtifactUserState value (which is itself [[[seconds, nanos]]]) wrapped at field 1.
Service definitions
CreateAccessRequest (n3dkHd). Sent when a non-collaborator opens a shared notebook URL and clicks "Request access". JS-bundle- verified; no HAR yet. TODO(har): trigger by opening a private share link from a logged- in account that lacks access.
CreateAccessRequest (n3dkHd). Sent when a non-collaborator opens a shared notebook URL and clicks "Request access". wire shape unverified.
Project sharing
GetProjectDetailsRequest. JS bundle confirms the canonical service name: JFMDGd → /LabsTailwindSharingService.GetProjectDetails. The Go-side field name `share_id` is historical; HAR shows the wire accepts the project_id (not a share-link slug). Captured against 12+ notebooks in NotebookLM web UI captures (2026-04-06..2026-04-23). Wire request: [project_id, [2]] [1] = [2] is an opaque mode flag (constant across all observed calls); other modes might surface different response payload shapes but have not been observed.
Field is named share_id for backwards compatibility with existing Go callers (api.Client.GetProjectDetails); on the wire this is the project UUID.
ProjectDetails. The captured response in our corpus carries only the collaborators payload, not the title/emoji/thumbnail that the fields below also model. The legacy fields are retained for backward compatibility with consumers of the generated protos and may populate under request modes other than [2] (none observed yet). HAR-verified shape: [ [<owner_entry>, <collaborator_entry>, ...], <flags|null>, // [true,true] when fully public, null o/w 1000, // opaque limit true, null, null, [3, true, true], // permissions blob (newer captures only) ] Entry per user: [email, role_int, [], [display_name, avatar_url]] role_int 1 = OWNER (the only role observed in single-user captures) api.Client.parseProjectDetailsResponse (client.go:4463) extracts only OwnerName + IsPublic.
populated from owner entry's display_name
populated from response [1] flags array
Collaborator list reflects the wire's primary payload.
Used as response type in: LabsTailwindOrchestrationService.GetOrCreateAccount, LabsTailwindOrchestrationService.MutateAccount
Used as field type in:
Used in:
Used in:
Real-time text transcript of user's speech
Real-time text transcript of AI host's speech
Text-to-speech lifecycle hooks
Audio payload transmission triggers
Control frame observed in live captures
Client-side media playback state sync
Microphone active/muted state sync
Connection diagnostics and state updates
AgentCommsPayload reconstructs the typed DataChannel payload at field 4. The sub-field numbers match AgentCommsMessageType values.
Used in:
AgentCommsUserMessage is the protobuf transmitted over the WebRTC DataChannel for real-time bidirectional UI and transcript synchronization.
Field 4 carries the typed event payload observed in live captures.
Used in:
Used in:
Used as response type in: LabsTailwindOrchestrationService.CreateArtifact, LabsTailwindOrchestrationService.GenerateArtifact, LabsTailwindOrchestrationService.GetArtifact, LabsTailwindOrchestrationService.RenameArtifact, LabsTailwindOrchestrationService.UpdateArtifact
Used as field type in: , , , ,
Note is a special type of Source
Video overview artifact
Used in:
Used in:
One suggestion pair. Pass description (optionally edited) as the instructions argument to CreateAudioOverview / CreateUniversalArtifact.
Used in:
Used in:
Video overview (confirmed from /tmp/notebooklm3.har)
ArtifactUserState is the per-user, per-artifact state the orchestration service persists. Today the only observed payload is a single repeated PlaybackPosition recording the user's last playback position in an audio overview; the field is repeated to leave room for additional markers (resume points, chapter offsets) that the UI may emit later. Wire shape (HAR-verified 2026-04-25): [[[seconds, nanos]]] That is: ArtifactUserState is a message with field 1 = repeated PlaybackPosition, and a single PlaybackPosition encodes positionally as [seconds, nanos].
Used in: , ,
AudioFormat captured kinds (HAR 2026-04-19+): 1 = "Deep Dive" — two-host conversation 2 = "Brief" — bite-sized overview 3 = "Critique" — expert review w/ feedback 4 = "Debate" — two-host opposing perspectives
Used in:
Audio length options (confirmed from /tmp/notebooklm2.har analysis)
Used in:
Shorter audio overview
~10-15 minutes
~15-20 minutes (longer)
Used as response type in: LabsTailwindOrchestrationService.CreateAudioOverview, LabsTailwindOrchestrationService.CreateAudioOverviewLegacy, LabsTailwindOrchestrationService.GetAudioOverview
Used as field type in:
Audio style types (confirmed from sqTeoe RPC in HAR analysis)
Used in: ,
"A lively conversation between two hosts, unpacking and connecting topics"
"A bite-sized overview to help you grasp the core ideas quickly"
"An expert review offering constructive feedback"
"A thoughtful debate illuminating different perspectives"
Encoding hints for batchexecute format
(message has no fields)
How to encode arrays
[[item1], [item2]]
[item1, item2]
[[[item1, item2]]]
How to handle empty/zero values
Used in:
Used in:
content holds inline markdown when this source is a note/text import (type=3). Leave empty for URL imports (type=2).
source_type matches the trailing enum int in the wire tuple: 2 = URL (url + title populated) 3 = NOTE (title + content populated)
Used in: , , ,
Used in:
Used in:
Used in:
Used in:
Used in:
Used in:
Used in:
1 = user, 2 = assistant
Used in:
Used in: ,
Used in: ,
Context information, structure inferred from usage
Used in:
1 = fast, 5 = deep
1 = running, 2 = complete, 5 = deleted
opaque report+sources payload
Used in:
Used in:
Used in:
Used in:
Used in:
Used in:
Used in:
Wire shape: [content, null, role]
1 = user, 2 = assistant
Used in:
Observed default request options: [2, null, [1], [1]]
Used in:
Used in:
Guide type for GenerateNotebookGuide (confirmed from /tmp/notebooklm3.har analysis)
Used in:
Text outline
Mind map visualization
Guidebook-related messages
Used as response type in: LabsTailwindGuidebooksService.GetGuidebook
Used as field type in: , ,
Used in:
Used in:
Used in:
Used in:
stun: and turn: URIs
empty for STUN entries
empty for STUN entries
Label is one autolabel cluster. The trailing "" in the wire tuple appears to be reserved for a per-label description (always empty in captures); not modeled here until a populated case is observed.
Used in: , ,
e.g. "Generated Code", "Testing", "RPC and Networking"
server-assigned UUID
members of this cluster
Used in:
Used in:
Used in:
Used as response type in: LabsTailwindOrchestrationService.CreateNote, LabsTailwindOrchestrationService.MutateNote
Used as field type in:
Used in:
Used in:
PlaybackPosition is a positional (seconds, nanos) tuple that mirrors google.protobuf.Duration's two int fields. Used inside ArtifactUserState to record the listener's place in an interactive audio overview.
Used in:
Used as response type in: LabsTailwindOrchestrationService.AddSources, LabsTailwindOrchestrationService.CopyProject, LabsTailwindOrchestrationService.CreateProject, LabsTailwindOrchestrationService.GetProject, LabsTailwindOrchestrationService.MutateProject
Used as field type in: ,
ProjectCollaborator captures the actual per-user wire entry. role_int observed values: 1 = OWNER. Other roles will appear once a notebook with multiple collaborators is captured.
Used in:
Used in: ,
or similar
bool something = 3; field 4 reserved/unknown field 5 reserved/unknown
or similar
Used in:
Used in:
Used in:
field 3 is null in observed responses
Used in:
Used in:
Used in:
Additional message not in sharing.proto
Used in: , ,
Used as response type in: LabsTailwindOrchestrationService.LoadSource, LabsTailwindOrchestrationService.MutateSource, LabsTailwindOrchestrationService.RefreshSource
Used as field type in: , , , ,
Used in: ,
Used in:
For text sources
For file upload
For URL sources
For YouTube
Used in:
Used in:
google.internal.labs.tailwind.common.v1.RevisionData revision_data = 4;
Used in:
Used in:
google.internal.labs.tailwind.common.v1.SourceIssue reason = 3;
Used in: ,
Used in:
Used in: , ,
Used in:
Field 1 carries the human-readable status string when present.
Used in:
Used in:
Used in:
Used in:
Used as response type in: LabsTailwindOrchestrationService.CreateVideoOverview
Used as field type in:
Video style (1=autoselect, 2=classic, 3=whiteboard)
Video style options (confirmed from /tmp/notebooklm3.har analysis)
Used in:
Let system choose the best style
Classic presentation style
Whiteboard-style presentation
Used in: