How to share an Apache Zeppelin notebook

Zeppelin sits very close to the cluster — that is its whole value. The interpreters bind to Spark, Flink, JDBC, and the notebook runs where the data is. It also means the notebook is behind whatever gate the cluster is behind, and the audience for a data result is usually wider than the set of people with cluster credentials.

What Zeppelin offers

The notebook URL. An authenticated route into the Zeppelin server. If your reader is on the VPN and has a Shiro or LDAP login, this works and is the best option. If they are not, it is a connection timeout.

Publish paragraph. The per-paragraph share menu produces an iframe URL that renders that one result. It is genuinely useful for embedding a chart into an internal wiki page — and it embeds from your Zeppelin server, so every reader of that wiki page still has to reach and authenticate against it. It moves the login wall inside an iframe rather than removing it.

Export as JSON. The note exports as .zpln — paragraphs, code, and stored results in one JSON file. Portable between Zeppelin instances, useless to a human without one.

Print to PDF. Available, flattens everything, and ends the conversation at the moment it should start.

The gap

Zeppelin results are frequently the input to a decision made by people who are not data engineers: a finance lead, a product owner, a regulator-facing analyst. They need the numbers at a URL that opens, as text they can quote, with somewhere to ask "does this include the backfill?"

Have the notebook publish its own report

Zeppelin paragraphs can write HTML directly, and each interpreter has an %html output mode. The pattern is to add one final paragraph that assembles the results and pushes them:

%spark
val summary = spark.sql("""
  SELECT day, sum(revenue) AS revenue, count(*) AS orders
  FROM sales WHERE day >= date_sub(current_date(), 30)
  GROUP BY day ORDER BY day
""").collect()

val rows = summary.map(r => s"<tr><td>${r(0)}</td><td>${r(1)}</td><td>${r(2)}</td></tr>").mkString
val html = s"""<!doctype html><meta charset="utf-8">
<style>body{font:15px/1.6 system-ui;margin:2rem auto;max-width:56rem}
table{border-collapse:collapse}td,th{border:1px solid #ddd;padding:.4rem .7rem}</style>
<h1>Revenue — last 30 days</h1>
<table><tr><th>Day</th><th>Revenue</th><th>Orders</th></tr>$rows</table>"""

// PATCH the same report id every run
import scala.sys.process._
Seq("curl", "-fsS", "-X", "PATCH",
    s"https://commareports.com/api/v1/reports/${sys.env("REPORT_ID")}",
    "-H", s"Authorization: Bearer ${sys.env("COMMA_API_TOKEN")}",
    "-H", "Content-Type: application/json",
    "--data-binary", "@-").#<(new java.io.ByteArrayInputStream(
      ujson.write(ujson.Obj("title" -> "Revenue — last 30 days", "html" -> html)).getBytes)).!!

Put the token in the interpreter's credential store rather than in a paragraph — notebooks get exported, and an exported .zpln carries every literal in it. A scoped token limits what a leaked credential can do.

Schedule it

Zeppelin has a per-note cron scheduler. Point it at this note and the report republishes on your interval, with a revision per run at one unchanging URL. That gives you what the publish-paragraph iframe never could: a link that works for readers with no cluster access, and a history of what the numbers were on each date.

What the comment layer changes

The reader who asks "does this include the backfill?" asks it on the row, and the answer stays there. Six weeks later, the next person to look at the same anomaly finds the explanation attached rather than re-opening the question in a channel.

Access is a setting on the report — private, team, domain-gated or link — so nobody needs a cluster account to read a number.

When to just send the notebook link

If your reader has Zeppelin access and is going to change the query, send the link. Interactive beats static for anyone who can get in. The published report is for the wider audience the cluster gate excludes, and for building a dated record the notebook's current state cannot provide.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Create your first report →

Related