What’s new

Every released version of Notch Metrics, newest first. Updates install from inside the app.

Download for Mac

Version 0.4.2

Patch Changes

  • Find the resize handle on the way in, not after you have passed it.

    The handle's target sat entirely inside the panel, so a pointer coming up at the notch from the screen below had to cross the bottom edge before the cursor changed, and the handle read as inert from the one direction people approach it. It now reaches a little past the edge, and the whole band is hittable when an update chip is sharing it.

Version 0.4.1

Patch Changes

  • Stop asking for your Keychain password on every refresh.

    A custom app that borrows a sign-in from another app read that app's Keychain item twice per refresh, and macOS prompts for a password each time one application reads another's item. The token is now held in memory until it expires, so the prompt happens once rather than on every tick.

  • A list widget fills its tile.

    The number of rows was a formula that came out at five for every 2x2 tile whatever its real height, while the server sends ten. Half the rows were thrown away and the space they would have filled was left empty. The tile now fits as many whole rows as it has room for.

  • Every widget starts at two by two.

    A sparkline or a plain figure used to start as a 2x1 while a gauge, a ring and a breakdown started taller. In the widget gallery that read as a fault: a short tile sat at the top of a card the height of its neighbours, and the gap underneath looked like a widget that had failed to draw. It is also the size every shape is good at. Anything that wants to be a strip is one drag away.

Version 0.4.0

Minor Changes

  • Show which account this Mac is signed in as, and let it sign out.

    The Account pane said "Signed in" and offered no way to leave. It now names the email, and carries a Sign out that revokes this Mac's device token on the server before forgetting it here — so the credential stops working rather than merely going missing, and it does not sit in your account's device list until it expires. Your widgets stay arranged; signing back in puts the numbers back.

    The email is read from the account and falls back to "Signed in" until the answer arrives, which on a cold launch is a moment and offline is forever.

  • Custom apps are app-first, and each one keeps its own log.

    Settings lists apps rather than metrics, with a credentials form, a reload and a remove that takes the app's widgets with it. Enabling an app approves what it asks for, so a cosmetic edit no longer revokes it and a widened host or a newly borrowed sign-in is named when it does.

    Every run writes what was asked for, what each metric answered, which hosts were called and what they returned. Open logs is in the app's three dot menu.

  • Open the app on a welcome screen in the notch, not a window of settings.

    Opening Notch Metrics used to open the settings window: a list of panes that are all empty until there is an account, with the one thing to do two clicks away. It now opens the notch itself, pinned, on a greeting — "hello", written out in the brand gradient — with a single Sign in button under it and nothing else. Escape closes it.

    Pinned matters for a reason worth knowing: the notch is a hover panel, and an unpinned one closes the moment the pointer leaves the few points it covers. A sign-in button that disappears underneath the pointer on its way to being clicked is a sign-in button that does nothing, which is what some people were hitting.

    While the browser has the handshake, the button says so — and hovering it offers Cancel, so a tab you closed or changed your mind about no longer leaves the notch waiting three minutes for a browser that is never coming back.

    An empty notch now carries an Add widgets button instead of a sentence naming two controls, the second of which only appears once you have pressed the first.

  • Four new widget shapes, and a row layout for wide tiles.

    A gauge draws a ratio inside a filled arc. Split, ranked and ring draw one list's categories against each other, each with a key naming as many as the tile has room for.

    A one-row tile wider than two columns now reads left to right. Stacked, it put the name on top and the figure in the middle and left everything past the second column empty.

Patch Changes

  • Widget previews are the size of the widget they preview, and the browser points at the docs.

    Every preview card was a flat 96 points, so a gauge or a breakdown was drawn into half the space it asks for and spilled over the card beneath it. Build your own now sits beside Back, and opens the guide to writing a custom app.

  • Say the right bucket, and how long a rate limit lasts, when a widget fails.

    Two copies of the one log line that explains a failing tile, and they had drifted. The batch's printed the widget's stored granularity — frozen when the widget is created, changed by no control since — while every request is built from the range instead. So a 30-day tile that asked the server for daily buckets was logged as having asked for hourly ones, which is the exact signature of a bug fixed long ago somewhere else entirely. A log that names a dead bug at the moment something is going wrong is worse than no log.

    The line now also carries retryAfterSeconds when the server sends it. It is the only number that says how long a rate limit has left, because a provider's own Retry-After is obeyed literally rather than fed into a curve of our own — and without it a limit that clears in a minute and a spend cap that will never clear on its own read identically.

    One copy now, so the next edit cannot land on half of them.

Version 0.3.2

Patch Changes

  • Fill in a widget added while the notch was already fetching.

    A tile dropped in from the browser sometimes previewed nothing at all — a skeleton beside a configure pane with the account picked and every setting right — and stayed that way for up to five minutes before a number appeared.

    Nothing serialised refresh(). It is called from the five-minute poll, the refresh button, connection adoption and the browser the instant a tile lands, and the batch behind it takes four to ten seconds, so two or three ran at once as a matter of course. Each one copied the whole states dictionary before its request and assigned the copy back after, which is a last-writer-wins overwrite of every tile including the ones it never asked about. A widget added while a batch was in flight did not exist when that copy was taken, so the commit removed its entry — and a tile with no entry renders as loading.

    Two changes. refresh() now runs one batch at a time with at most one caller queued behind it, chained rather than joined: a caller that attached itself to the request already in flight would be answered about a notch that did not contain its own widget. And the results are merged per widget rather than assigned, under three conditions — only the widgets that run asked about, only where nothing newer has answered since, and only while the widget is still asking the question that was sent. The last of those also retires a quieter bug, where a slow batch could paint a stale figure under a range the user had already moved on from.

    refreshOne answers a single picker change in well under a second and was the most frequent loser of the race it is meant to win.

  • Give the share card real glass, the provider's name, and one size.

    Four changes to the same picture.

    The plates were flat black rectangles. .ultraThinMaterial is what the notch uses, but a material samples the window behind it and ImageRenderer declines to draw one at all, so the exported card never had frost in it — only a tint. The card now draws the background twice, blurs the second copy and masks it to the plates, which is the same effect built out of things the renderer does draw. The tint over it went from 55% to 62% black, so a pale wallpaper cannot wash the figure out.

    The footer pill credits the provider first, then a hairline, then Notch Metrics. A card posted on its own said where the screenshot was made but not what it was of.

    The size menu is gone and every card is a 2x2. A share card holds one tile with nothing to pack around it, so the span is a composition decision rather than the user's: a 1x1 came out a stamp in the middle of a 1080px square and a 6x2 left a letterbox of wallpaper above and below it.

    The background menu is a four-column grid in a popover. A menu row is one line of text and one 18pt image, which is as much of a picture as AppKit will put in front of a choice — and the choice here is the picture. The Haze set joins Aurora and Anime, two of which left.

  • Make the installer window look like it belongs to the app.

    White, with the icons centred and the instruction along the bottom. The window used to be a dark gradient with everything sitting two thirds of the way down it — the Finder draws an icon's name in dark text inside a disk image whatever the background is, so "NotchMetrics" and "Applications" were charcoal on near black, and the first thing anybody saw of this app was a label they had to squint at.

    The arrow between the two is the mark's own: the brand ramp along it, magenta leaving the app and amber arriving at the folder, finished with the open chevron the icon ends on rather than a plain triangle.

  • Fill a tile in a second when its range changes, rather than in ten.

    Changing a widget's settings refetched the whole notch. That request is serialised per connection and answers only when its slowest group has, so the one tile somebody was looking at waited behind every other integration in the layout — eight to ten seconds with a few payment providers and a GitHub account ahead of it. A skeleton held that long does not read as a slow fetch, it reads as a widget that never loads.

    The tile whose settings changed is now fetched on its own. The whole batch is still what a poll does, and still what answers a widget with no account yet.

Version 0.3.1

Patch Changes

  • 0.3.0 was built pointing at http://localhost:8787 and could not reach anything. It is withheld; this is the same app against the real servers.

Version 0.3.0

Minor Changes

  • The Integrations pane has a search field above the list. It matches a connector's name, tagline and keywords as well as its metrics' labels, so "mrr" finds the providers that can show you one — the same matching the widget browser uses, rather than a second one that disagrees with it. Categories with nothing in them drop out while you type.

  • Tiles are clickable. A click opens the number where it lives: the metric's own page where the connector declares one — a GitHub tile goes to its repository's stargazers, issues or Actions, filtered to the branch the widget names — and the provider's dashboard otherwise. The configure pane's new Opens field overrides both, for anyone whose useful destination is their own board rather than the provider's.

    Connectors declare dashboardUrl, and a metric may declare a linkTemplate whose {param} placeholders the widget's own parameters fill. Both are catalogue fields, so a provider that moves its dashboard fixes every existing tile with a Worker deploy rather than an app release.

  • A GitHub CI widget: point it at a repository and, if you want, one branch, and it lists the last ten Actions runs newest first, each with its outcome as an icon — passed, failed, still running, or skipped.

    List rows now carry a state beside the provider's own status, so a tile can draw an outcome without matching on a provider's vocabulary; a metric can also declare freshnessSeconds, which this one sets to a minute. Without it a CI feed would inherit the daily bucket's fifteen-minute cache and could report a build that had since gone red.

    Public repositories only, for now: this connection asks GitHub for public_repo, because the read-only alternative for private ones does not exist for an OAuth app.

  • The app now keeps a log on disk at ~/Library/Application Support/NotchMetrics/logs/app-<date>.log: every request with its status and timing, every failed widget with the server's own reason, and the build and server it started against. Five days are kept. Anything shaped like a token or a key is blanked before it is written.

    A tile that fails on one range and not another, or only on one person's account, previously left nothing behind to look at — the unified log needs Console.app and cannot be handed to anybody.

    Switching a widget's range also no longer leaves the previous range's number on screen when the new one fails. The last good figure is still held through a provider blip, but only while it answers the same question; a 30-day total under a title reading "7d" is worse than the error it was standing in for.

  • Refresh the numbers that can actually move, and say when you are

    MetricDescriptor.freshnessSeconds existed but only GitHub's CI feed used it; everything else sat on the granularity's fifteen minutes. Now every metric that moves faster than its bucket says so.

    Payments, revenue, orders and refunds re-read every 60s — a payment is an event rather than a figure, and a feed of them is the one tile somebody watches because it changes. Subscription figures every 3 minutes, developer counts every 2, spend and CRM every 5.

    Product analytics, Search Console and YouTube are deliberately untouched. Their data is delayed at the source — Search Console "runs two to three days behind", in this repository's own words — so a faster poll spends a daily quota to get the identical number back. The connector is what knows how fast its data moves, which is why this lives on the descriptor rather than in a table keyed on MetricId: YouTube's revenue and Stripe's are not the same number.

    The client follows, or the TTL is academic: 30s with the notch open, 60s on AC, 180s on battery, and unchanged under Low Power Mode, thermal pressure, a metered network or sleep. A faster poll costs a cached round trip rather than somebody's rate limit — the TTL is what bounds provider calls, whatever the client asks for.

    Tiles also show a small spinner in the corner the share icon uses while a fetch is in flight. Refresh deliberately keeps the last number on screen rather than blanking the tile, so until now nothing said a figure was being checked at all.

  • The notch now gets out of the way when an action opens a window somewhere else. Connecting an account, signing in and opening Settings all used to leave the panel pinned on top of the browser tab or window they had just brought forward.

    A connect flow started from the notch also comes back to it. Finishing one always landed on the Settings Integrations pane, which threw away the widget you were half-way through configuring; now it reopens on the pane you left, and only a flow started from Settings stays in Settings.

  • Notifications, and a notification centre in the notch

    Providers now declare what they can notify about in their manifest, so a new provider's notifications ship with a Worker deploy and no app release — the same property widgets already have. The Worker evaluates the enabled ones on the cron it already runs, reusing the series it was fetching anyway, so the feature costs no extra provider calls.

    The Mac shows them in a two-column pane inside the notch, connections on the left. A new one drops out of the notch as a round app mark, falls clear, then opens into a card with the headline and a line of detail — and goes back the same way, closing to a circle before it rises, so it reads as being swallowed rather than deleted. Clicking it opens the provider's own dashboard.

    There is no UNUserNotificationCenter involved and so no permission prompt, no entitlement and no Info.plist change: the notch is already on screen, so the app owns the presentation.

    Honest about what it is: notifications arrive within about five minutes for polled providers, and nothing is delivered while the Mac is asleep. This is a log you catch up on, not a pager.

    Per-connection notification toggles live in Connections, beside rename and disconnect: what Stripe is allowed to tell you is a fact about your Stripe connection rather than an app-wide preference. The Notifications pane keeps what genuinely is app-wide — whether banners show, how long they stay, the sound, quiet hours — and links across.

    A notification can also make a sound. Silent by default — adding audio to every existing install on an update reads as a bug rather than a feature — with a curated shortlist in Settings that previews each one as you select it.

    Fixes a latent fault in AppSettings while adding preferences to it. It decoded through Swift's synthesised initialiser, which ignores property defaults and throws on any key the file does not have, so the first release to add a preference would have silently reset every existing user's launch-at-login, display choice, hover timings and approved plugins. It now decodes field by field, and a test pins it with a real pre-notifications settings file.

    Also moves the existing five-minute metrics refresh onto the same energy gate. It previously ran unconditionally — on battery, in Low Power Mode, with the lid shut — and stopRefreshing() had no callers. On an eight-hour sleep that was ~96 wake-ups and 96 hits against the user's provider rate limit.

  • Notch Metrics updates itself. The Updates pane checks the release feed, offers the version it finds, downloads it, checks it and swaps the app over, and a coloured chip in the bottom corner of the notch says so without anybody going looking in Settings.

    The installing half already existed. What is new is everything that decides whether to install anything: a six-hourly poll, the build-number comparison, the download with a progress bar, and the states the pane draws. A build this Mac cannot run reads as up to date rather than as a failure, a half-written download is thrown away rather than offered, and a verified one survives a relaunch so quitting mid-update does not mean fetching it again.

    The feed is the Worker's, with the bucket as a fallback for the case the Worker is down. A 404 from the Worker is treated as an answer rather than as a reason to read the bucket, which is what keeps PINNED_VERSION able to pull a bad release back.

Patch Changes

  • Line the account picker up with the fields above it

    A SwiftUI pop-up button does not fill the width it is given: it hugs its title and centres inside the slot. The 200pt frame that lines the picker up with the Name field was therefore leaving half the spare width as a gap to its right, and putting the control's edge somewhere different from every text field in the pane. Trailing alignment puts it back on the same line.

  • Changing a widget's settings now visibly refetches it. The tile drops to its loading skeleton — or to the last number it has for the range you picked — instead of leaving the previous window's figure sitting there, and the request for the settings you just moved off is cancelled rather than left to land on top of the new one. Rapid changes coalesce into one fetch instead of one per keystroke.

  • The download button goes through the release feed rather than reading the bucket directly, so withholding a release withholds it from the website as well as from the app. Release notes are at notchmetrics.com/changelog, generated from the app's own changelog.

  • Fix widget ranges erroring on the AI connectors. A widget froze its bucket when it was created — the first one its metric listed, which is hour for both OpenAI and Claude — and kept sending it as the range moved, so a 90-day tile asked for ninety days of hourly buckets and the connector refused a walk it could not finish. The bucket now follows the range, the way the server and the range picker already assumed.

  • "Mark all read" in the notification centre now actually marks the rows read. The inbox held read state alongside the notifications rather than on them, and every row, badge and bold title reads it off the notification itself, so the button changed only the count in the sidebar and left the list looking untouched. Marking one connection read also told the server to clear the whole inbox, which another Mac would then agree with.

  • Steadier resize handle: the pointer turns into a resize cursor the first time it reaches the handle rather than the second, the panel's bottom edge no longer eases and snaps on two clocks while the handle is held, and letting go settles onto the row instead of jumping to it.

    The "+3 below" label is now a button — a chevron centred just above the handle that scrolls down a screenful, and hides once the last widget is in view.

  • The range picker now offers only the ranges a metric can actually answer for. Every connector has declared which buckets its metrics support since the first one shipped, and nothing read it — all five ranges were offered for everything, so picking one the metric could not serve came back as an error on the tile. On the AI connectors that was "12m" on any metric and "24h" on spend, which both report once a day. A widget already saved on a range its metric cannot serve is moved to the nearest one that works when its settings are opened.

    Changing a setting no longer resets the widget's size. The configure pane held a copy of the widget taken when it opened and wrote the whole copy back on every edit, so resizing a tile with the pane still open and then touching any control sprang it back to the size it had been.

Version 0.2.0

Minor Changes

  • A GitHub connection is now the account, not one repository.

    Connect GitHub once and pick the repository on each widget, so a notch can watch several repositories without a connection each. Widgets made before this keep the repository their connection was created with. Adds a Followers widget, which reads the account and needs no repository.

  • Add a RevenueCat connector with six widgets: MRR, revenue over the window with a comparison to the window before, active subscriptions, active trials, and RevenueCat's 28-day new and active customer counts.

    Connect it with a v2 secret API key that has Charts & Metrics read. A key that can also list projects is named after the project; one that cannot works too, provided the project ID is typed in. A key that can see several projects is asked to pick one rather than having one chosen for it.

    Figures come from RevenueCat's own Overview and revenue endpoints, so they match the dashboard. Money arrives as decimals and is converted to minor units per currency, so a yen figure is not multiplied by a hundred.

  • Polar and Paddle are now live connectors, and every payment provider gains a Recent payments widget.

    Polar reads MRR, revenue, active, new and churned subscriptions from Polar's own metrics endpoint, so the figures match its dashboard, and lists the latest paid orders. Paddle totals paid and completed transactions by billing date, normalises active subscriptions to a monthly amount for MRR, counts starts and cancellations across the subscription book, and lists the latest transactions with the customer embedded. Both take an environment alongside the key, since neither API lets the host be inferred from the token.

    Recent payments is a list widget: the tile shows the latest ten payments as rows, with who paid, what for, how much, and how long ago, rather than a single figure. It is available on Stripe, Dodo Payments, Lemon Squeezy, Polar and Paddle. A series can now carry rows on the wire; an older app ignores them.

  • The notch shows real numbers. Widgets now refresh from the API in one batched request on launch, every five minutes, and immediately after one is added. The seeded Stripe tiles are gone — a new notch starts empty and says so — and Custom Metrics is parked until it is revisited.

  • Widgets resize by dragging handles on their corners and edges, to any span that fits the grid, instead of a button that cycled four presets. Edit mode has a proper dot grid behind opaque cards. Nothing can overlap.

  • Added an Integrations pane listing every connector we know about, grouped by what it measures, each with its own icon and a single Connect button. Connect opens the browser to finish authenticating and the app picks the connection up as soon as it lands.

  • Browse and add widgets inside the notch. Add Widget now opens a sidebar, a search field and the widget list in the notch itself instead of a separate window at the bottom of the screen, and a widget is added by clicking it rather than dragging it across the display. The configure pane that follows commits with Add, and Cancel takes the new widget back out.

    Signed out, the notch opens on a sign-in panel — a line of explanation and one blue Sign in button — instead of a grid of tiles each reading "Sign in".

    Signing in refreshes everything built from the connections list: the Apps pane, the connections list, the widget browser and the configure pane's Account picker, instead of leaving the signed-out answer on screen. A widget whose provider has exactly one account is pointed at it, so tiles added before signing in stop reading "Connect Stripe" with Stripe connected; one whose provider has several says "Pick a connection" instead.

    A tile's hover badges — share, configure, remove — are dark frosted glass with a larger glyph, instead of a small white disc with a glyph too small to recognise.

    Double-clicking a widget enters edit mode with that tile selected, and pressing Delete removes the selected widget. Edit mode was otherwise a half-second long press nobody finds, or a button at the other end of the header from the tile being moved.

  • The notch is a grid only. The list view, its toggle and everything that existed for it are gone.

  • Added a list view, grouped by the app each number comes from, and made every widget belong to an app rather than guessing from its metric name. The header toggles between grid and list; the grid says how many widgets it could not fit and offers the view that can.

    Hover now opens and closes instantly, and closing is governed by the panel rather than by the notch strip — moving down into the panel no longer shuts it.

  • First working version: the notch opens on hover and shows a grid of metric tiles over frosted glass, with an edit mode for rearranging and a handle for changing its height. Custom metrics can be authored from any MCP client.

  • Dodo Payments and Lemon Squeezy are live: MRR, revenue and active subscribers from both, plus refunds from Lemon Squeezy. Three working revenue connectors now instead of one.

  • Widgets is now a browser: search across apps and widgets, open an app to see its widgets and connections, then pick a widget, point it at a connection and watch a live preview before adding it to the notch. Apps and widgets carry search keywords, so "churn" finds churned subscribers and "seo" finds Search Console.

  • Charts sit at the bottom of a tile, filled with a gradient that fades to nothing. Dodo Payments draws in its lime rather than its near-black primary. Chart colour, fill and fill opacity are all per-widget configuration now, so a new widget sets them rather than patching the app catalogue.

  • Share a metric as an image. Hovering a tile now shows a share button in its top-right corner, which opens a screenshot editor: the card in the middle, and a bar underneath with frame size, background and widget size. The preview updates as you change them, Download writes a PNG at the frame's real pixel size, and Copy puts it on the pasteboard. Backgrounds are eight dark pictures plus the brand gradient, and every card is signed with the Notch Metrics mark at the bottom.

  • The share card is one card again: the tile sits straight on the background with its own dark surface instead of on a second rounded plate, and it is smaller, so the picture around it has room. The signature sits in a tinted glass pill, and no longer slides below the crop on backgrounds whose aspect ratio overflows the frame.

    Every background is new — twenty wallpapers from the Aurora and Anime sets, grouped in the picker — and the editor gains a Chart menu: Line, Bars or None, applied to the card only and never written back to the widget.

    The editor's controls float over the card in one pill instead of sitting in a toolbar strip. The dropdowns are icon and chevron only, with the caption and current value in the tooltip, and the row collapses in two stages as the window narrows so Copy and Download are never the controls pushed off the end. The window's surface is one dotted, frosted field running the full height, behind the title bar included.

  • Shopify is connectable, in beta: sales, orders, average order value, refunds, new customers, total customers and a feed of recent orders.

    Connect it with a custom app made in your Shopify admin — the store's .myshopify.com domain and an Admin API access token, with read_orders and read_customers. A token that has only one of the two still connects; the widgets it cannot read are greyed out rather than failing later.

    Totals are in the store's own currency rather than converted into the one your account prefers, and the tile says so when the two differ. Sales are gross, so a refund does not remove the order from the day it was paid — the Refunds widget is the other half, and it buckets by the order's date because that is the date Shopify gives us. Average order value is the window's own ratio of sales to orders, not the average of the daily averages.

    Orders are read in bounded pages, so a store doing more than six hundred orders in the window reports a total marked as an undercount rather than exhausting Shopify's rate limit mid-walk.

  • Added a Connections pane listing every connected account, with rename and disconnect, and an Add connection button that goes to Apps. Integrations is now called Apps, because it lists what you can connect rather than what you have. Every new connection gets a name automatically — "Stripe — Acme Inc" — disambiguated when two accounts would otherwise read the same.

  • The grid is a flow. Widgets run left to right and top to bottom, resizing one pushes the rest along to make room, and nothing can be stranded in empty space. Header icons are centred on the part of the panel you can actually see.

  • Widget numbers sit in the middle of the tile, left aligned, so figures line up across tiles of different heights. Every widget now carries its own format — k/M/B compaction, the number type, decimals and affixes — chosen when the widget is added and overriding what the series reports.

  • Use the current Google Analytics and Search Console logos, and swap the Apollo connector for GitHub. Search Console's old mark was being shown because simple-icons still ships the pre-2021 glyph; Analytics was the right shape but flattened to white, which lost the amber that makes it recognisable.

  • Tiles whose number depends on a time window now carry that window in their title, after a middle dot: Revenue · 30d, Visitors · 7d. Snapshots such as MRR, active subscribers or stargazers keep their plain title, since the range would not change them. The same rule decides whether the configure pane offers a Range control, so the two can no longer disagree. Gallery previews follow it too.

  • The notch fills in much faster when you open it. Metrics for different connections are now fetched at the same time rather than one after another, so a first load waits for the slowest connection instead of all of them added together, and tiles show their last known number straight away while the new one is on its way.

    A tile that is still waiting now shows a placeholder shaped like the tile it is about to become — a figure-sized bar, and a chart-shaped one underneath when the widget draws a chart — instead of telling you to connect an app you have already connected. A widget whose account was disconnected, or reconnected somewhere else, says "Pick a connection" rather than reporting an error, and rebinds itself when there is only one account to pick.

  • YouTube is connectable, in beta: views, watch time, average view duration, subscribers, new subscribers, likes and comments for a channel you own.

    Sign-in uses the same Google client as Analytics and Search Console, so there is nothing new to authorise beyond the channel's read-only scopes, and the hour-long token refreshes in the background. Pick the channel after signing in — a brand account's channel is rarely the one the sign-in name suggests.

    Everything time-ranged comes from one YouTube Analytics report, so average view duration is watch time over views for the whole window rather than the mean of the daily averages. The subscriber total is YouTube's own, which it rounds above a thousand; the change against the previous window is the exact net gain, so the arrow is right even where the total reads as 12,300. New subscribers is gross, so it does not match that change.

Patch Changes

  • The Google Analytics and Search Console marks are drawn in their own colours again. Silhouetting them in white, as GitHub's mark is, turned the Analytics logo into a generic bar chart.

  • Fix sign-in from the Settings window, which opened the browser without its PKCE challenge and could only ever show "this link is missing information".

  • Opening the widget gallery now collapses the notch instead of pinning it open; it comes back while a tile is being dragged in and steps aside again after the drop.

  • A notch with more than twelve widgets now loads at all. The server caps a metrics batch at twelve and rejects the whole body past that, so a thirteenth widget made every tile read "Could not reach Notch Metrics". Requests are split to fit, and a rejected request, an ended trial and a signed-out app each say so instead of blaming the network.

  • Fix the notch after a widget is dragged in from the gallery: the gallery now notices the drop rather than waiting thirty seconds and reappearing on its own, the configure pane the drop opens is no longer closed out from under it, and a collapsed notch never reopens on a stale form instead of the grid.

  • The account picker in a widget's settings no longer stretches past the pane when the connection has a long name.

  • The Google Ads and Meta Ads brand marks no longer ship in the app bundle, following those connectors being withdrawn. Both keep their name and accent in the app catalogue, so a custom metric that names either still reads as itself rather than as "Custom" — it draws an SF Symbol now instead of a vendored logo, the way Linear already does.

  • Move refresh and settings to the left of the notch header, beside the app name. The right half carries the edit pill, the below-fold count and the close button, and on a notched display it begins immediately after the camera housing — so the two controls reached for most often sat furthest from the pointer.

    Fix the edit-mode well, which was framed larger than the grid and offset outwards. Inside a ScrollView that overflows the viewport, so its left and right bands were clipped and the dots stopped dead at the outermost tile whatever the inset was set to. It is now the background of a padded grid, and the padding is the gutter — so the gap around a tile matches the gap between two of them.

    Stop the header being squeezed: the panel sized the header band 10pt shorter than the band draws itself and counted none of the content's padding, so SwiftUI reclaimed the difference from the header's top padding.

    Add a widget gallery. "Add Widget" sits beside Done in edit mode and opens a translucent window listing every widget each connector offers, grouped the way the server groups them. A widget is dragged from there onto the notch, lands where the pointer let go, and opens a configuration window for its account, size, number format, chart and range.

    Use the shapes mark for Widgets everywhere it appears.

    Remove the Widgets settings pane. The gallery replaces it end to end — browse, drag in, configure — and a second way to add a widget that works differently is worse than one. notchmetrics://settings/widgets still resolves, to Apps.

    Configure widgets inside the notch rather than in a window of their own. A split: the tile on the left, its controls on the right, with the grid sliding out and the pane sliding in. A second window thrown on screen over whatever the user was working in — with its own focus and activation to manage — was the wrong shape for changing the thing already on screen.

    Hide the range and chart controls for metrics that cannot use them. A snapshot — GitHub's stargazers, forks, open issues — is whatever it is right now: there is no series to draw over thirty days and no previous window to compare against, so both controls changed nothing.

    Name the connection on a tile, not the app. Somebody with two Stripe accounts had two tiles both saying "Stripe". Each widget can be given its own name from its configuration, prefilled with the connection's; changing it renames that tile only, not the account.

    Refetch a widget when its configuration changes. Switching account or range updated the stored widget but left the tile showing the old number until the five-minute timer came round.

    Draw bar charts with a solid fill. They used the sparkline's top-down falloff, which made a short bar read as a faint one — a second meaning the chart does not have.

  • Add OpenAI and Claude as API-key connectors, under a new "AI" category: token volume, request counts and daily spend.

    Each provider is given the metrics it can actually answer for. OpenAI's usage report carries a request count and Claude's does not, so Claude offers no api_requests rather than an invented one.

    Two ways the money goes wrong, written down because both look right: Claude's cost report returns a decimal string already in cents, so reading "123.78912" as dollars overstates the bill a hundredfold, and OpenAI returns a float in dollars, which has to round to minor units once per bucket rather than per line item.

    Both usage APIs cap a response at 31 daily buckets, so a window is a page count, not a call. The walk is bounded at four requests: a 90-day range drops its comparison window to stay inside that and keeps the number, and a year is refused with a message rather than by the Worker's CPU limit.

    Cost is a separate reach from usage on both admin APIs, so a key that can read tokens but not dollars connects with api_spend greyed out instead of being rejected — but only on a refusal, since availableMetrics is written once at connect and a transient 503 would hide spend until the user reconnected.

    Both connectors ship their own brand mark on the brand's own tile: OpenAI's blossom white on black, Claude's sunburst white on #D97757. simple-icons carries neither at the title the sync script would look for, so both are committed as overrides rather than derived at build time.

  • Polar and PostHog now carry their real marks and colours.

    Polar is monochrome — a white mark on near-black — not the blue it was given, which belongs to Polars, the dataframe library at pola.rs. With no brand hue to tint a chart line, Polar's graphs are white. PostHog gains its full-colour hedgehog on the dark backdrop it is drawn for, keeping its orange for charts.

  • The resize handle at the bottom of the notch now shows a resize cursor and lights up on hover, and the "+N below" count sits beside it instead of in the header.

  • Sparkline charts are no longer cut off at the edges of the tile. A peak could be drawn flat against the top, troughs sank through the floor, and the dot marking the latest value was clipped on the right of every chart — and sliced across the top as well whenever the most recent value was also the highest. The curve now stays inside the chart, which also means it no longer draws a value higher than any the metric actually reported.