Skip to content

Web version of broadcasts: public issue pages, team archive and "view in browser" link #63

Closed

Description

@clbotdev

Background

Newsletter tools give every issue its own public web page, which search engines can find. They also offer a "view in browser" link and a per-publication archive. beehiiv, Substack and Kit all have this, and Marc Lou's MailCheap (open source, a "cheaper beehiiv" on your own SES, launched 17 Oct 2026) lists it as a headline feature: "Every issue gets its own web page that search engines can find."

SendLit doesn't have it today. The only public routes are /track/*, unsubscribe and /health. Nothing renders a broadcast as a web page, there's no archive, and no merge tag links to a browser version. That's a gap for the newsletter persona, and it loses SEO and discovery that would otherwise compound for senders. Comparisons with beehiiv and Substack will mark SendLit down on it.

Proposed fix

Data and API

  • Add web publishing settings per broadcast: webPublished (bool, default off, or a team-level default), slug, publishedAt, seoTitle, seoDescription, ogImage, noindex.
  • Add team-level archive settings: archiveEnabled, a title and description, and an optional custom domain later.
  • Expose these in @sendlit/api-contract and the OpenAPI doc, plus read endpoints so platforms can render the archive themselves:
    • GET /web/issues: a paginated list of published broadcasts for a team, giving title, slug, publishedAt and excerpt.
    • GET /web/issues/:slug: rendered, sanitized HTML plus metadata.
  • MCP tools for publishing and unpublishing, so agents can manage it too.

Hosted pages (SendLit-hosted option)

  • A public issue page at /{team-handle}/p/{slug}, or on a team subdomain. It renders the broadcast HTML with all personal and tracking content removed (see below).
  • A public archive at /{team-handle}, listing published issues newest first, with a subscribe form that creates a contact (so subscriber:added sequences fire).
  • SEO tags on both: title and description, a canonical URL (or a sender-supplied canonical when a platform hosts the page), Open Graph and Twitter tags, Article JSON-LD, an RSS feed and a sitemap, plus noindex when the sender asks for it.

Email side

  • A {{web_version_url}} merge tag (a "view in browser" link) and an optional default footer link when the issue is published.

Safety

  • Before rendering on the web, strip merge-tag personalization, unsubscribe and tracking links, open pixels and any per-contact content. Fall back to a generic value for each personal field.
  • Unpublished or draft broadcasts return 404. Unpublishing removes the page and the sitemap entry.
  • Sanitize HTML (no scripts), and cache with sensible headers.

Embedded and platform use (CourseLit and others)

Acceptance criteria

  • A broadcast can be marked "publish to web" in the UI, through the API and through MCP. It gets a stable slug, and the setting can be turned off again.
  • Published issues render at a public URL, with no personal data, tracking pixels or unsubscribe tokens. Tests cover this.
  • A team archive page lists published issues and includes a working subscribe form that creates a contact and triggers subscriber:added.
  • Pages include title, meta description, canonical, OG and Twitter tags, and Article JSON-LD. The noindex option is respected. An RSS feed and sitemap are generated.
  • The {{web_version_url}} merge tag works in broadcasts and resolves to the public page.
  • GET /web/issues and GET /web/issues/:slug are in api-contract and OpenAPI, so a platform can render the archive itself.
  • Unpublished or deleted broadcasts return 404 and are removed from the sitemap and RSS feed.
  • Docs page explaining web publishing and the platform API option.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestseverity: mediumNotable gap with a workaround, or competitive parity

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions