Python SDK
pip install sealmetrics does not workThe Sealmetrics Python SDK is built but not yet released to PyPI. There is no installable package, and the code on this page will not run today. It is documented here as the design reference for the release.
What to use instead, right now:
| You want | Use |
|---|---|
| A typed client in any language | Generate one from the OpenAPI 3.1 spec — see For AI Agents |
| Plain HTTP from Python | Quick Start — httpx or requests against the REST API |
| Analytics inside an AI assistant | The MCP server — no code at all |
| A DataFrame | POST /stats/query/export returns CSV; pandas.read_csv() it. See Multi-Dimensional Query |
We will update this page the day the package ships.
The Sealmetrics Python SDK is a type-safe client for the Sealmetrics Analytics API, designed for data scientists and analytics professionals. It wraps the REST API with Pydantic models, native pandas/polars DataFrame conversion, magic date shortcuts, automatic pagination, and retries.
There is also a Node.js SDK, but it is deprecated, and likewise not published to npm.
Features
- Type-safe: full Pydantic models with IDE autocompletion
- DataFrame integration: native pandas and polars support
- Sync and async: both clients built on
httpx - Magic dates: shortcuts like
"30d","mtd","ytd" - Automatic pagination: fetches all results seamlessly
- Automatic retries: exponential backoff for reliability
- Bulk exports: download large datasets efficiently
- Batch queries: multiple queries in a single request
Installation
The commands below are what installation will look like once the package is published. They fail today — there is no sealmetrics project on PyPI.
The package will be published as sealmetrics and requires Python 3.10+.
pip install sealmetrics
# With pandas support (recommended for data scientists)
pip install sealmetrics[pandas]
# With Jupyter support (pandas + progress bars)
pip install sealmetrics[jupyter]
# With polars support
pip install sealmetrics[polars]
# All optional dependencies
pip install sealmetrics[all]
Authentication
The SDK authenticates with a Sealmetrics API key. Generate one in Settings → API Keys (it starts with the sm_ prefix and is shown only once).
API keys are read-only: they hold the stats:read, sites:read, and accounts:read scopes, which is exactly what the analytics methods below require. Write operations (such as creating or updating segments) need a JWT session instead. See Authentication and API Tokens for details.
from sealmetrics import Sealmetrics
client = SealMetrics(
api_key="sm_live_xxxxx", # Settings → API Keys
account_id="acc_123"
)
Client initialization
The main entry point is the SealMetrics class.
from sealmetrics import Sealmetrics
client = SealMetrics(
api_key="sm_live_xxxxx",
account_id="acc_123",
base_url="https://my.sealmetrics.com", # Set explicitly (see note below)
timeout=30.0, # Request timeout (seconds)
max_retries=3, # Retry attempts
show_progress=True, # Progress bars (requires tqdm)
)
# Use as a context manager for proper cleanup
with SealMetrics(api_key="...", account_id="...") as client:
df = client.pages("30d").to_df()
| Argument | Default | Description |
|---|---|---|
api_key | — | Sealmetrics API key (required) |
account_id | — | Account to query (required) |
base_url | https://api.sealmetrics.com | API base URL. ⚠️ Always pass https://my.sealmetrics.com explicitly — the built-in default points at a host that does not currently serve the API. |
timeout | 30.0 | Per-request timeout in seconds |
max_retries | 3 | Retry attempts with exponential backoff |
show_progress | True | Show pagination progress bars (if tqdm is installed) |
Magic dates
Most methods accept a period as the first argument. You can use a shortcut, a Period enum, or an explicit date range.
# Relative periods
client.pages("today") # Today
client.pages("yesterday") # Yesterday
client.pages("7d") # Last 7 days
client.pages("30d") # Last 30 days
client.pages("90d") # Last 90 days
client.pages("12m") # Last 12 months
# To-date periods
client.pages("wtd") # Week to date
client.pages("mtd") # Month to date
client.pages("qtd") # Quarter to date
client.pages("ytd") # Year to date
# Named periods
client.pages("this_month")
client.pages("last_month")
client.pages("this_year")
client.pages("last_year")
# Explicit date range
client.pages("2025-01-01", "2025-01-31")
Analytics methods
Query methods return a QueryResult (see below) unless noted otherwise. They accept the period arguments plus optional filters (utm_source, utm_medium, segment, sort_by, page_size, max_pages, …).
Traffic analytics
| Method | Description | Returns |
|---|---|---|
overview() | Dashboard metrics with time series | OverviewData |
pages() | Page-level metrics | QueryResult[PageMetrics] |
landing_pages() | Entry page metrics | QueryResult[LandingPageMetrics] |
time_series() | Daily time series | QueryResult[TimeSeriesPoint] |
realtime() | Real-time visitors (last 5 min) | dict |
Traffic sources (UTM)
| Method | Description | Returns |
|---|---|---|
sources() | By utm_source | QueryResult[SourceMetrics] |
mediums() | By utm_medium | QueryResult[MediumMetrics] |
campaigns() | By utm_campaign | QueryResult[CampaignMetrics] |
channels() | GA4-style channels | QueryResult[ChannelMetrics] |
Geographic and device
| Method | Description | Returns |
|---|---|---|
countries() | By country (ISO codes) | QueryResult[GeoMetrics] |
devices() | Device / browser / OS breakdown | DeviceBreakdown |
Conversions
| Method | Description | Returns |
|---|---|---|
conversions() | Conversions by type | QueryResult[ConversionMetrics] |
microconversions() | Microconversions | QueryResult[MicroconversionMetrics] |
funnel() | Funnel analysis | FunnelReport |
Example
from sealmetrics import CompareMode, Period, Sealmetrics
client = SealMetrics(api_key="sm_live_xxxxx", account_id="acc_123")
# Dashboard overview with year-over-year comparison
overview = client.overview("30d", compare="yoy")
print(f"Pageviews: {overview.traffic.page_views}")
print(f"Bounce rate: {overview.traffic.bounce_rate}%")
if overview.comparison:
print(f"YoY change in entrances: {overview.traffic.entrances_change}%")
# Pages as a DataFrame (automatic pagination)
df_pages = client.pages("30d").to_df()
print(df_pages.head())
# Filter to paid traffic only
df_paid = client.sources("mtd", utm_medium="cpc").to_df()
# Top countries
df_countries = client.countries("30d").to_df()
top10 = df_countries.nlargest(10, "entrances")
# Device breakdown
devices = client.devices("30d")
print([(d.device_type, d.entrances) for d in devices.devices])
# Funnel analysis
funnel = client.funnel("30d")
print(f"Overall conversion rate: {funnel.overall_conversion_rate}%")
# Real-time visitors
realtime = client.realtime()
print(f"Active visitors (5 min): {realtime['active_visitors']}")
# Type-safe period and comparison enums
overview_typed = client.overview(Period.MONTH_TO_DATE, compare=CompareMode.PREVIOUS)
Generic query
For endpoints without a dedicated method, use query():
data = client.query(
"/stats/properties/breakdown",
start="30d",
property_key="plan",
)
QueryResult
Query methods return a QueryResult, which behaves like a list of typed models and adds DataFrame conversion.
result = client.pages("30d")
# Metadata
print(result.total)
print(result.has_more)
# Conversions
df = result.to_df() # pandas DataFrame
df_pl = result.to_polars() # polars DataFrame
dicts = result.to_dicts() # list of dicts
# Iterate directly
for page in result:
print(f"{page.path}: {page.page_views} views")
Segments
Segments are saved filter configurations exposed via client.segments. Reading segments works with a read-only API key; creating or modifying them requires a write-capable session (see Authentication).
# List all available segments (including built-in system segments)
for seg in client.segments.list_all():
print(f"{seg.name}: {seg.display_name}")
# list() is an alias for list_all()
custom = client.segments.list_all(include_system=False)
# Get details by ID or name slug
segment = client.segments.get("paid-spain")
# Use a segment in a query
df = client.pages("30d", segment="paid-spain").to_df()
df = client.sources("mtd", segment="paid-spain").to_df()
Segment management methods (write scope required):
# Create a segment
segment = client.segments.create(
name="paid-spain",
display_name="Paid Traffic Spain",
filters=[
{"field": "utm_medium", "operator": "eq", "value": "cpc"},
{"field": "country", "operator": "eq", "value": "ES"},
],
color="#F59E0B",
)
# Update, duplicate, delete
client.segments.update("paid-spain", display_name="Paid Traffic Spain (CPC)")
my_organic = client.segments.duplicate("organic-search", "my-organic")
client.segments.delete("paid-spain")
See Segments for the underlying REST resource.
Bulk exports
For large datasets, use client.exports instead of paginating.
# Estimate export size first
estimate = client.exports.estimate("pages", "30d")
print(f"Estimated rows: {estimate.estimated_rows}")
if estimate.can_stream:
# Stream small exports (< 10K rows) directly
df = client.exports.stream_df("pages", "30d")
else:
# Create an async export job
job = client.exports.create("pages", "30d", format="csv")
# Wait and download as a DataFrame
df = client.exports.download_df(job.job_id)
# Or download raw bytes
content = client.exports.download(job.job_id)
with open("export.csv", "wb") as f:
f.write(content)
Export types: pages, sources, mediums, campaigns, countries, devices, browsers, os, conversions, microconversions, time_series, landing_pages.
Other export helpers: estimate(), create(), get_status(), list_all(), cancel(), wait(), download(), download_df(), stream(), stream_df(). See Exports.
Batch queries
Reduce latency by fetching multiple datasets in one request via client.batch.
# Execute arbitrary batch queries
results = client.batch.execute([
{"id": "overview", "endpoint": "/stats/overview", "params": {"period": "30d"}},
{"id": "pages", "endpoint": "/stats/pages", "params": {"period": "30d", "page_size": 100}},
{"id": "sources", "endpoint": "/stats/sources", "params": {"period": "30d"}},
])
overview = results["overview"]
# Dashboard shortcut: overview + top pages + top sources + channels + devices
dashboard = client.batch.dashboard("30d", compare="previous")
print(dashboard["overview"])
print(dashboard["top_pages"])
print(dashboard["channels"])
client.batch also exposes validate() to check queries without executing them. See Batch Requests.
Async support
Use the async methods (prefixed with async_) for concurrent operations.
import asyncio
from sealmetrics import Sealmetrics
async def analyze():
async with SealMetrics(api_key="...", account_id="...") as client:
overview, pages, sources = await asyncio.gather(
client.async_overview("30d"),
client.async_pages("30d"),
client.async_sources("30d"),
)
return overview, pages, sources
overview, pages, sources = asyncio.run(analyze())
Error handling
All SDK errors inherit from SealMetricsError.
from sealmetrics import (
Sealmetrics,
AuthenticationError,
AuthorizationError,
RateLimitError,
ValidationError,
NotFoundError,
SealMetricsError,
)
try:
data = client.pages("30d")
except AuthenticationError:
print("Invalid or missing API key")
except AuthorizationError:
print("No access to this account")
except RateLimitError as e:
print(f"Rate limited, retry after {e.retry_after}s")
except ValidationError as e:
print(f"Invalid parameters: {e.message}")
except NotFoundError:
print("Resource not found")
except SealMetricsError as e:
print(f"API error: {e.message} (status={e.status_code}, request_id={e.request_id})")
The full exception hierarchy: SealMetricsError (base), AuthenticationError, AuthorizationError, RateLimitError (with retry_after), ValidationError, NotFoundError, ConflictError, ExportError, NetworkError, TimeoutError, and ServerError.
Pagination
Paginated query methods fetch all pages automatically by default. You can control this behavior with arguments:
# Default: fetch everything (auto-pagination)
all_pages = client.pages("30d")
# Top 100 only — a single page
top_pages = client.pages("30d", max_pages=1, page_size=100, sort_by="page_views")
The returned QueryResult exposes total and has_more so you can inspect the result set. For very large datasets, prefer bulk exports. See Pagination & Sorting for the REST-level details.
See also
- Authentication — API keys, scopes, and JWT sessions
- Stats Endpoints — the REST endpoints the SDK wraps
- Segments, Exports, Batch Requests
- Rate Limits