Ship changelogs
in under five minutes.

Install the widget, connect GitHub, and let ShipLog turn commits into polished product updates.

Quick start

Paste one script tag before closing body.

Find your widget ID in the dashboard under Widget. Replace sl_YOUR_WIDGET_ID below.

html
<script
  src="https://www.getshiplog.site/widget.js"
  data-widget-id="sl_YOUR_WIDGET_ID"
></script>

By default a floating What's new button appears in the corner of the page, with an unread count badge when there are new entries. To use your own button instead, add data-shiplog-open — see Custom triggers.

Custom triggers

Open the changelog from any button in your app.

When at least one custom trigger exists anywhere on the page, the floating button is hidden automatically — your trigger takes over, unread badge included.

Data attribute (no JavaScript)

html
<button data-shiplog-open>What's New</button>

<script src="https://www.getshiplog.site/widget.js" data-widget-id="sl_YOUR_WIDGET_ID"></script>

Attach by selector

javascript
ShipLog.attach("#changelog-btn");
ShipLog.detach("#changelog-btn"); // cleanup

React / Next.js

tsx
useEffect(() => {
  ShipLog.attach("#changelog-btn");
  return () => ShipLog.detach("#changelog-btn");
}, []);

Or put data-shiplog-open on your button — no effect cleanup needed.

GitHub sync

Keep your changelog current without manual imports.

ShipLog reads commits and merged pull requests from your connected repo, rewrites them with AI, and creates changelog entries.

Easiest setup: open your project in the dashboard and click Auto-sync. ShipLog registers the GitHub webhook for you.

Manual webhook (optional)

If you prefer to configure GitHub yourself, use this payload URL:

url
https://www.getshiplog.site/api/webhook/github
FieldValue
Content typeapplication/json
EventsPushes, Pull requests
SecretMust match GITHUB_WEBHOOK_SECRET

You can also hit Sync Manually in the dashboard anytime for a manual pull. Duplicate entries are skipped automatically.

Script options

Configure the widget via data attributes on the script tag.

AttributeDefaultDescription
data-widget-idrequiredYour project widget ID
data-positionbottom-rightCorner for the default floating trigger: bottom-right, bottom-left, top-right, top-left
data-badge-color#ef4444Background color of the unread count badge
data-badge-positiontop-rightCorner of the unread badge on its trigger: top-right, top-left, bottom-right, bottom-left
html
<script
  src="https://www.getshiplog.site/widget.js"
  data-widget-id="sl_abc123"
  data-position="bottom-left"
  data-badge-color="#4f46e5"
  data-badge-position="top-left"
></script>

Next.js

Add the widget to your root layout.

tsx
// app/layout.tsx
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <script
          src="https://getshiplog.site/widget.js"
          data-widget-id="YOUR_WIDGET_ID"
          async
        ></script>
      </body>
    </html>
  )
}

For static sites, WordPress, Shopify, or Webflow — paste the script tag before </body>. Same snippet everywhere.

Widget API

Control the panel programmatically.

The script exposes window.ShipLog as soon as it loads.

MethodDescription
ShipLog.attach(selector)Bind click on matching elements
ShipLog.detach(selector)Remove listeners
ShipLog.open()Open the changelog panel
ShipLog.close()Close the panel
ShipLog.refresh()Refetch entries (returns a Promise)
ShipLog.getUnseenCount()Current unread entry count — build your own badge UI with this
ShipLog.markAllSeen()Clear unread state without opening the panel
javascript
document.addEventListener("shiplog:ready", () => {
  console.log("Widget ready");
});

document.addEventListener("shiplog:seen", (e) => {
  console.log(`Cleared ${e.detail.count} unread entries`);
});

Events dispatched on document: shiplog:ready, shiplog:open, shiplog:close, shiplog:update, shiplog:seen — fires when unread entries are marked read, either by opening the panel or calling markAllSeen().

Unread tracking

ShipLog stores the last time each visitor saw the panel in localStorage, scoped per widget. Entries published after that timestamp count as unread and show up as a small badge on every trigger. First-time visitors see a badge for all existing entries rather than a blank count. Opening the panel marks everything seen immediately — it does not wait for the visitor to scroll through entries.