You just built a Gemini pipeline. It generates great output — structured analysis, technical breakdowns, research summaries. Now you need to share it with someone who doesn't have a terminal open.
Your options: copy-paste into Google Docs (fight with formatting), save to a file and Slack it (watch it disappear in 20 minutes), or build a custom viewer (spend a week on something that isn't your actual project).
Or: three lines of code.
The Setup
pip install google-genai surfacedocs
You'll need two API keys:
- Google AI API key from aistudio.google.com
- SurfaceDocs API key from app.surfacedocs.dev (free tier, no credit card)
The Minimal Example
import os
from google import genai
from surfacedocs import SurfaceDocs, SYSTEM_PROMPT, GEMINI_DOCUMENT_SCHEMA
# Initialize clients
client = genai.Client(api_key=os.environ["GOOGLE_API_KEY"])
docs = SurfaceDocs(api_key=os.environ["SURFACEDOCS_API_KEY"])
# Generate structured content with Gemini
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="Write a technical overview of WebSocket protocol vs HTTP polling",
config={
"system_instruction": SYSTEM_PROMPT,
"response_mime_type": "application/json",
"response_schema": GEMINI_DOCUMENT_SCHEMA,
},
)
# Publish to SurfaceDocs
result = docs.save(response.text)
print(result.url) # https://app.surfacedocs.dev/d/...
That's it. Gemini generates structured content, SurfaceDocs renders and hosts it. Click the URL and you've got a formatted, shareable document.
What's happening under the hood
The key is three things the SurfaceDocs SDK provides:
-
SYSTEM_PROMPT— Instructions that tell Gemini how to structure its output into document blocks (headings, paragraphs, code blocks, tables, lists) -
GEMINI_DOCUMENT_SCHEMA— A JSON schema specifically shaped for Gemini'sresponse_schemaparameter, so output is guaranteed to be valid structured JSON -
docs.save()— Takes that JSON, pushes it to SurfaceDocs, returns a URL
The SDK ships with both GEMINI_DOCUMENT_SCHEMA (for Gemini's native structured output) and OPENAI_DOCUMENT_SCHEMA (for OpenAI's response_format). Same idea, different shapes for each provider's API.
A More Realistic Example: Multi-Step Pipeline
In practice, you probably have a pipeline that does real work — not just a single generation call. Here's a two-step pattern: generate raw analysis, then format it as a publishable document.
import os
from google import genai
from surfacedocs import SurfaceDocs, SYSTEM_PROMPT, GEMINI_DOCUMENT_SCHEMA
client = genai.Client(api_key=os.environ["GOOGLE_API_KEY"])
docs = SurfaceDocs(api_key=os.environ["SURFACEDOCS_API_KEY"])
# Step 1: Generate raw analysis (unstructured)
raw = client.models.generate_content(
model="gemini-2.5-flash",
contents=(
"Compare FastAPI, Flask, and Django for building REST APIs in 2026. "
"Cover performance, developer experience, ecosystem, and when to pick each."
),
)
print(f"Generated {len(raw.text)} chars of analysis")
# Step 2: Format as a SurfaceDocs document
formatted = client.models.generate_content(
model="gemini-2.5-flash",
contents=f"Turn this analysis into a well-structured document:\n\n{raw.text}",
config={
"system_instruction": SYSTEM_PROMPT,
"response_mime_type": "application/json",
"response_schema": GEMINI_DOCUMENT_SCHEMA,
},
)
# Step 3: Publish
result = docs.save(formatted.text)
print(f"Published → {result.url}")
Why two steps? Your first call does the actual thinking — analysis, comparison, research. It can be freeform, messy, detailed. The second call just reshapes that output into SurfaceDocs' block format. You get the best of both worlds: unconstrained reasoning followed by clean formatting.
This also means you can plug SurfaceDocs into any existing pipeline. Whatever your agent or chain produces, just add a formatting step at the end and save it.
Organizing with Folders
As your pipeline generates more documents, you'll want to organize them. Pass a folder_id to route documents into specific folders:
# Publish to a specific folder
result = docs.save(
formatted.text,
folder_id="your-folder-id"
)
Create folders in the SurfaceDocs dashboard and grab the ID from the URL. Useful for pipelines that produce daily reports, per-client analyses, or categorized research.
When This Clicks
This pattern works best when:
- Your pipeline runs on a schedule — Daily market analysis, weekly reports, automated monitoring summaries. Each run produces a document with a permanent URL.
-
You're sharing with non-technical stakeholders — Your PM, your client, your CEO doesn't want to
cat output.json. They want a link. - Your agent produces work products — Research agents, analysis agents, documentation generators. The agent does work, and that work needs to live somewhere.
- You're prototyping fast — You're iterating on a Gemini pipeline and want to see formatted output without building a viewer. SurfaceDocs becomes your instant preview layer.
The Full Pattern
Here's the general flow for any Gemini pipeline:
Your pipeline (any logic)
│
▼
Raw LLM output (unstructured)
│
▼
Gemini + SYSTEM_PROMPT + GEMINI_DOCUMENT_SCHEMA
│
▼
docs.save() → Shareable URL
The structured output step can go anywhere — at the end of a chain, after post-processing, or directly as your only generation call. SurfaceDocs doesn't care what your pipeline does upstream. It's just the output layer.
Get Started
pip install google-genai surfacedocs
Free tier gives you 10 documents/month with 90-day retention — plenty to try it out. Pro ($19/month) bumps that to 1,000 docs with unlimited retention when your pipeline goes to production.
The full code examples from this article are on GitHub.
SurfaceDocs is the output layer for AI pipelines. pip install surfacedocs and stop building custom viewers.
Top comments (0)