Share a whylogs report
whylogs profiles datasets instead of copying them: sketches, counts, distributions, null rates — a summary small enough to log every run. Comparing two profiles gives you a drift report, which is the closest thing an ML team has to an early warning.
The warning then fires inside a notebook or a job log, which is the one place the people who caused the drift will never look.
Render the drift report
import whylogs as why
from whylogs.viz import NotebookProfileVisualizer
target = why.log(df_today).view()
reference = why.log(df_baseline).view()
viz = NotebookProfileVisualizer()
viz.set_profiles(target_profile_view=target, reference_profile_view=reference)
viz.write(
rendered_html=viz.summary_drift_report(),
html_file_name="drift", # → drift.html
)
Self-contained HTML: per-column distributions, the drift statistic, the two histograms side by side. The side-by-side is the part that matters — a drift score alone is a number people argue with, and two overlaid distributions is an observation people act on.
Publish it
Drop drift.html into Comma, or from the job:
import requests, os
requests.patch(
f"https://commareports.com/api/v1/reports/{os.environ['REPORT_ID']}",
headers={"Authorization": f"Bearer {os.environ['COMMA_API_TOKEN']}"},
json={"title": f"Drift — features_v2 — {run_date}",
"html": open("drift.html").read()},
).raise_for_status()
Scripts run inside a sandboxed iframe (allow-scripts, no allow-same-origin),
so the report's interactive column views keep working. See the
API reference and publishing from CI.
Drift is a cross-team message
The useful thing about a drift finding is almost never "retrain the model". It
is "column plan_tier gained a category on Tuesday" — a fact about an upstream
pipeline, owned by a team that does not use your notebook, your MLflow, or your
scheduler.
A URL is the only form of that message which survives the trip. With anchored comments, the reply lands on the column:
- "We added
enterprise_trialin the billing migration — expected." - "Null rate on
regionjumped because the CDN header changed."
That exchange, on the evidence, is the entire loop. See commenting on HTML.
One URL, a revision per run
PATCH the same report id from a scheduled job and the URL becomes the standing drift page for that dataset. Each run appends a revision, so the question "has this been creeping for a month or did it break yesterday?" is answered by scrubbing the history rather than by digging out old notebooks.
Pair it with a routine if you want the publish scheduled rather than wired into an existing job.
Who can see it
Per report: private, your team, anyone signed in at your domain, or anyone with the link. Profiles are summaries rather than rows, but a sketch over a small segment can still be revealing — use domain or team access. See sharing & access control.
Limits
- Entry HTML: 5 MB. A report over hundreds of columns can approach it — profile the feature set the model actually uses.
- Assets: 25 MB per file, 250 MB and 500 files total.
- 60 requests/minute per token.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.