Changelog

Every update to Adswish, with timestamps. Download the full history as a PDF for your records.

Download PDF
  1. v9.27.0

    The top bar comes back when you drag for it, and the on-device model is yours to talk to

    • A first visit no longer reloads itself. The PWA's worker claimed the page and fired the same event an update uses, so every brand-new visit paid a visible full-page reload — the worker now only reloads when you press Refresh and the handover is one you asked for.
    • Hid the top bar in Customize and want it back? Drag down from the top edge: a slim grab strip brings the real header back (sidebar toggle, notifications, theme, customize, and the new Intelligence button), and it tucks itself away again after a few seconds, on Escape, or if you drag it back up. It works on every dashboard page, including the chat's home screen.
    • The Intelligence button now has two homes: a permanent one in the header, and the first tile of the Home panel, which used to deliberately omit it.
    • Opening Customize blurs the page behind it, so the dialog reads as a layer instead of a flat overlay.
    • On-device AI is now a conversation, not a download. The page has a real prompt box that streams the answer token by token, with Stop and Clear, and the loaded model is offered in the chat's model picker as **On-device** — the same model in the same tab, so the download is shared rather than repeated.
    • The on-device model can run the assistant's actions too, and it still cannot act around a gate: the browser proposes a tool call, and the server executes it through the same parse → access tier → money-needs-Full → confirmation card → audit path the hosted model uses. Money actions still require Full access and still ask for approval, whichever model is answering.
    • The model catalog's three Qwen ids were verified against the installed WebLLM prebuilt list, so a download can no longer fail on a name that does not exist.
    • Loading a model is per-tab and survives leaving the page; unmount only cancels a download in flight, instead of throwing away a finished 447 MB model.
  2. v9.26.0

    Strict CSP: every page is served with a per-request nonce

    • Inline scripts now need a per-request nonce. The site policy and the stricter admin policy each carry a fresh nonce minted by the server for that response, and 'unsafe-inline' is gone from script-src everywhere — an injected script from another origin can no longer run.
    • The admin area keeps its stricter policy pair (no framing, form actions and frames locked to our own origins) enforced alongside the site policy, exactly as before.
    • This makes every page dynamically rendered — the trade-off the research flagged, accepted for the security gain. Pages still stream and are still cached at the edge.
  3. v9.25.0

    The agent's cockpit: customization, right-click lookup, twelve real skills, and an on-device model you can download

    • The Customize panel is real: the button beside the light/dark switch opens a centered dialog with five font choices, five chat colours (the shade your replies and the typing indicator use), five theme accents, and a switch that hides the top white bar so only the blue loading rule remains.
    • Right-clicking selected text in a chat now offers Look up (opens a web search in a new tab), Check the glossary (searches the real Adswish glossary and links to the matching guide), and Copy — styled to match the app in both light and dark.
    • You can now switch each platform skill (Briefs, Boards, Discovery, Spyder, Lens, Templates, Social Inbox, Swipe File) on or off, and add your own named skills for the agent — stored on your device and removable at any time.
    • The assistant can do more of the campaign work itself: list your campaigns, open a campaign's details, list applications, pause a live campaign, and duplicate a campaign into a new draft — each shown in the skills list with a plain answer about what it asks first.
    • On-device AI is now real: with a WebGPU browser you can download a small open model (Qwen 3.5 0.8B by default, up to Qwen 3 4B on a bigger GPU) straight into your browser, watch the progress, and unload it when you are done. Your prompts never leave your machine — the only network traffic is the one-time model download.
    • The agent's access control now explains itself: Limited (asks before every action), Full (routine actions run without asking), money actions always ask for approval on either tier, and Ultra (2FA for every action) is clearly marked as not available yet.
    • The ad-copy draft generator now has full test coverage (it had shipped without any), and two honesty fixes in the agent's campaign tools: an unreadable database now says so instead of claiming you have no campaigns, and the money-action refusal path is pinned by a test so it can never silently rot.
  4. v9.24.0

    A new workspace: one screen, two sidebars, and an assistant that shows its working

    • The AI workspace is now one screen. The chats panel and the main navigation sit side by side on the left, the conversation fills the rest, and the only thing that scrolls is the conversation itself — no more scrolling the page up and down to reach the box or your history.
    • Everything with AI in it — Library, Skills, Plugins, Explore, Spyder, Boards, Lens, Briefs, On-device AI, your chats and projects — now lives on the AI sidebar, and everything else (campaigns, applicants, payments, analytics, tracking, messages, disputes, plan, profile, settings) stays on the main navigation, so neither list is crowded out by the other.
    • The assistant's skill catalogue (Skills) and its integrations (Plugins) are now two separate tabs of one sheet, with a plain answer on every row about what the assistant may do on its own, what it asks first, and why something is unavailable — instead of letting you click into a refusal. A new preview row announces Computer use (coming soon).
    • The message box gained a model picker for your own AI connection, a Think toggle for slower and more deliberate answers, file attachments, voice input, and quick-start chips (Summary, Code, Design, Research) that appear on a fresh chat and step aside once the conversation starts.
    • The composer shows one clean outline when you press into it, and the blue rule under the top bar is now a real loading bar that sweeps during navigation.
    • The top bar was slimmed to what belongs there — notifications, the light/dark/desktop switch, the agent-ready indicator and your profile — and everything else moved into the profile menu, which now opens as a proper account panel: switch account, Account, Dashboard, Help center (with its own menu), Guides, Dark mode and Log out.
    • The bottom-left corner of the navigation now shows the country you set in Settings with its flag, replacing the Log out button there (Log out lives in the profile menu).
    • Project folders in the AI sidebar: group campaigns into named folders, tick what you are working on, and the assistant works with those. The ticked list follows you across the suite.
    • Campaign briefs, the campaign Boards, Lens analytics and Spyder were all restyled into the same design language as the Library and Skills pages.
    • Adding a payment card during business setup now offers the real method tiles (card, and PayPal/Apple marked as not yet available rather than pretending to work).
    • The app can be installed to your phone or desktop from Settings → App, with honest steps for each browser — including the two-tap path Apple requires instead of a button that could never work.
    • Account notices — tracking disconnected, payments paused — used to sit across the page pushing everything down. They are now corner popups you can dismiss with an ×.
    • The appearance settings (theme, font, accent, background) no longer break on browsers that block storage: the choice applies for the session and nothing crashes.
    • The AdSwish wordmark appears once in the workspace (top left) and now takes you to the AI chatbox when pressed; the duplicate on the AI panel is gone.
    • Signed-out visitors no longer trigger a failing account-appearance request on the pages they can see (such as the account-paused page): the read now happens only when you are signed in, and when it does run its response is always fully read, so a page can finish loading cleanly instead of hanging on a request that never completes.
  5. v9.23.3

    A page can no longer save as the wrong account after a switch in another tab

    • Adswish keeps one sign-in per browser, shared by every tab. That is deliberate — but it meant a tab left open could, for a moment, save under an account different from the one it was showing. Earlier releases noticed the switch and blocked the page; this one closes the remaining gap on the server itself. Every dashboard action now carries a short-lived proof of the account its page was rendered for, and a request whose proof does not match the account it is signed in as is refused and the page reloads once. A tab whose browser had frozen its scripts while another tab switched accounts can no longer write to the wrong one.
    • The proof is a tab-level fact, never a cookie: cookies are shared by tabs, which is the whole reason the problem existed.
    • Signing in with a password failed for a short period this evening with a generic error. A safeguard added in the same release called the browser's request function in a way the browser rejects, which stopped every request on the site, not just sign-in. It is fixed and the failure is now pinned by a test, and the live site has been checked end to end: creator and business accounts signed in, in two tabs of one browser, with the switch correctly announced.
    • The safeguard also reloads a page that is genuinely out of date only once, so a stale page cannot cause a reload loop.
  6. v9.23.2

    A saved card now actually stays saved

    • Saving a payment card — from the payments page or during business setup — looked like it worked. The card form accepted the card and reported success, but the card was never attached to your account, so the page kept asking you to add one. The fault was ours: we opened the card form without telling Stripe which customer it was for, so Stripe collected a card and then had nobody to give it to. The form is now always opened for a specific, existing customer, which means the card lands on your account the moment you finish.
    • The payments page also stops saying “Add a card” while our confirmation is still on its way: when a single card is already saved, it is shown straight away and made the default.
    • A business can only ever have one Stripe customer record. If saving is interrupted — a retry, a double click, two tabs open at once — the next attempt reuses the record that already exists instead of creating a second one, and a record created earlier is found again even if our own note of it was lost. Where duplicates already exist, the oldest is used and the case is flagged internally.
    • Cards saved before this release were collected but left attached to nobody, so they could not be used for future charges. Adding a card again now saves it properly; nothing is charged by saving a card.
    • A billing profile we could not read used to be treated as “this business has no card yet”, which is exactly how a second customer record could be created. It now asks you to try again instead of guessing.
  7. v9.23.1

    The directory pages were sizing themselves to whatever happened to be in them

    • The business and creator directories were sizing themselves to their contents instead of to their container. With few entries listed, the whole page narrowed — and the amount it narrowed by changed as entries were added or removed, so two visitors could see two different page widths. Both pages now fill the width they were designed for every time.
    • The same flaw was quietly making our own screenshot comparison of those two pages unreliable: the box we blank out before comparing sits inside that container, so it moved whenever the listing changed. With the width fixed, that comparison now measures the page rather than the data, and both pages are pinned so the width cannot drift again.
    • Our screenshot comparison was also recording two things no visitor ever sees: a badge that only exists while the site is being developed, and the cookie-consent notice, whose appearance depends on whether the visitor has already made a choice. The comparison now represents a visitor who has already chosen and ignores the development-only badge, so what it reports is a real change to the site.
    • A check of the dispute form could fail while the form was working correctly. It looked for the error message at the moment the request was sent, rather than after the answer came back, so when the machine was busy it could see a form that was still in progress. It now waits for the answer. Nothing about the form itself changed.
  8. v9.23.0

    A page could wait forever for the database, and two buttons could jam forever on a bad connection

    • Every page now waits for the database with a deadline instead of forever. If the connection stalled part-way through loading a page, the page simply hung — no error, no content, just a spinner that never stopped. Each read now has a deadline, and when it runs out the page degrades the way it would for any other missing piece of data instead of freezing. The checks that decide whether you are signed in, and what you are allowed to do, are the deliberate exception: if they cannot get an answer, you are treated as signed out rather than waved through — an unanswered question never grants access.
    • Two kinds of button on your campaign page could jam forever. If your connection dropped at the exact moment you approved work, rejected a submission, accepted an applicant or paused a campaign, the button kept its spinner for the rest of the session and no message appeared. They now recover and say plainly that the request failed, and you can simply try again. The same guard was added to the creator-rating form.
    • Someone opening a campaign that is not theirs is now turned away before the page does any other work. The page used to run three further database reads before refusing them; now the refusal comes first.
    • This release also adds Vercel Web Analytics — a simple, privacy-friendly count of which pages are visited. It uses no cookies and collects no personal information.
    • A blank value in the part of your account you can edit yourself could hide the account type we hold for you on the Intelligence pages, showing the wrong sidebar for the session. The one shared answer to “what kind of account is this” is now pinned at that page too, so the editable copy can never mask the real one.
    • A test-harness detail with an outsized effect: a warning about missing keys was being printed by our own test plumbing on any page test with three or more side-by-side elements — noise that hid real warnings. Fixed and pinned at the source.
    • Two things this release recorded rather than repaired: an end-to-end pilot spec intermittently loses its page stream on the local test stack, and the monthly-payout step of our full test-mode money drill did not produce its invoice rows. Both are in our review log with next steps; the drill's money movement itself — charge, hold, release, transfer — passed exactly.
  9. v9.22.2

    Two hands posting into the same agent mailbox could pick the same message number, and one damaged line could take the whole inbox down

    • Every message one agent sends to another carries a number that must be unique. Two agents posting at the same moment could each read the mailbox in the gap before either had written, and end up picking the same number, so one message could quietly cover another. Sends now take turns under a lock — one that is broken open if its holder crashes, so a crashed session cannot wedge the mail — and a burst of simultaneous sends is proven to produce a distinct number every time.
    • A mailbox line damaged in storage — not merely unreadable, but the wrong shape underneath — used to bring the whole inbox down with an error while it was being listed, so the perfectly readable mail behind it went unseen. Damaged lines are now set aside and counted out loud, and the count is printed, so damage is visible rather than silent. One bad line can no longer hide the good ones.
    • Our own record of what previous sessions left behind was measured line by line across the last sixty days: orphaned commits, a dropped stash and every unmerged branch were each compared against the current tree. Nothing recoverable was found — everything left behind had already landed, in evolved form — and the two branches that cannot be safely merged are now written down with the reason each is deliberately excluded. The handoff mailbox's own instructions also now describe exactly what is checked when a message is sent, instead of claiming more than the code does.
  10. v9.22.1

    Release checks now include the browser, and root-level imports resolve correctly

    • Release verification now requires browser console, network and server-log evidence, with unresolved problems reported rather than hidden behind a successful build. Integration ideas must be checked against available APIs and connected services before implementation.
    • A repository check incorrectly treated a root-level configuration file as a directory and reported tracked dependencies as missing. Root-relative imports now resolve correctly, with regression tests for existing and missing targets.
    • Local agent handoffs now have an addressed mailbox with work references and acknowledgements. Messages coordinate work but do not transfer permissions or file ownership.
    • An onboarding test could click Continue before its simulated plan restoration finished. Its router fixture is now stable, restored state is awaited and saving must settle before cleanup; payment behavior is unchanged.
    • Cloud-only local configuration is not yet ready and has not replaced the protected local configuration file. This release does not claim every account role, historic finding or redesign task is complete.
  11. v9.22.0

    Nine of our own permission checks could have been stepped around by the person they were checking, and three of them guard your money

    • Parts of the site that need to know who you are ask two questions before letting you through: what kind of account this is, and whether you are allowed to do this. Nine of those checks were answering the first question from a field on your own profile, which your account can rewrite for itself, rather than from the part of your account only we can change. Anyone signed in could have altered that one field and walked straight past, and because the check was the thing making the call, nothing behind it looked a second time. Three of the nine sit on money: the page that shows whether your card is ready to be charged again, the pages that change what is on your subscription, and the page showing your tracking status. All nine now read the one part of your account that only we can change, from one single place, so there is no second copy of that answer left to drift out of step.
    • The check that existed for exactly this purpose could not see it. It looked for role comparisons of one particular shape, and these nine had nothing to compare against, because only a single value was ever read, which is precisely what made them unsafe. That shape is now covered too, and the case that was added to prove it was built from the actual fault rather than from the pattern we had assumed, so it would genuinely have caught it.
    • Two of the checks that run before anything reaches you were answering the wrong question. The one that runs before a change is saved was reading the files on the machine rather than the set of changes about to be recorded, and the one that runs before anything is published was verifying a copy of the code rather than the code that would actually go out. Both now judge what is really being shipped, and the published-code check builds a complete fresh copy of the whole repository and verifies that, because a partial copy cannot tell you what is genuinely there.
    • A change could have put back a file that had been deliberately broken apart and removed, with nothing objecting. The file was not on the machine, but it was queued to be added, and every check that would have noticed was looking at the machine. A new check now refuses to record a change that adds a file which is not there. It runs at the moment of saving rather than as one of the automated tests, because once a deleted file is back in the history it looks exactly like one that never left.
    • A batch of supporting work went out with these. A change to the database could not be replayed from scratch, so a clean rebuild stopped partway through; it now applies cleanly, and the checks about scheduled background jobs report what they actually verify instead of what they assume. The daily sweep that returns unspent campaign money no longer runs long enough to be cut off. The secret used to recognise a genuine internal request was replaced without stranding the confirmations it had already given, because replacing that kind of secret carelessly quietly invalidates every live record while looking like a security improvement. A claim made in an earlier entry on this page about that sweep was corrected rather than quietly restated. A piece of the repository was invisible to the check that stops anything being published without the files it depends on; that has been extended, though the tracker app at the edge of the repository is still outside what it can see. Per-account dashboard settings, a shared look for the legal pages and the guides, and one colour system for the whole app with a new check that catches a style referring to a colour that does not exist, also ship in this release.
    • A page we built to help businesses check their tracking pixel was telling them everything was fine when nothing had actually been saved. The heartbeat itself does reach us: a live campaign recorded one earlier the same day, which had been blocked on preview and staging builds until a gap in our own content rules was closed two days earlier. But the check page decided it was working from the fact that the request came back, and the request comes back whether or not anything is written, so a business whose campaign was paused, or was not one the heartbeat applies to, was shown a confident all-clear over a heartbeat that saved nothing at all. Nothing about the pixel is changed in this release; the over-confident check is recorded here and in our review log instead, because a green light that cannot fail is worse than no green light.
    • The list of what each part of the site is allowed to do was maintained by hand, so a new part could be added with no line saying what it was for, and a line could exist for a part that was not there at all. The list is now derived from the site itself, and a check refuses two parts claiming the same address.
    • The same answer to what kind of account this is was being worked out in twenty separate places. Where it had been copied rather than shared, a gap in the handling of money was hiding in the gap between the copies, and consolidating it into one place closed that gap.
  12. v9.21.0

    A garbled request could have removed your paid add-ons, and the account area had no request limits at all

    • A request to change your add-ons that arrived damaged — truncated in transit, or sent with a body we could not read — was being read as "you want no add-ons". Rather than refusing it, the system carried it out, quietly removing the add-ons you had paid for and issuing a credit for them. Your add-ons are now left alone and the request is refused. A missing add-on list is treated the same way: only an explicit empty list, which is what the dashboard actually sends when you remove the last one, still removes anything.
    • The pages behind your signed-in account had no limit on how many requests a single account could make. Most of them are harmless, but two of them change billing: one asks for a refund, and one changes what is on your subscription. Neither was capped, so a script or a stuck browser could have driven them in a loop. Every signed-in account area is now limited per account, and the billing actions carry a tighter limit than the rest. If a limit is ever reached, the request is refused before anything is changed — never halfway through.
    • One endpoint recorded your cookie and analytics consent choices, and was deliberately open to anyone so that people visiting before signing in could choose. That is the right design, but it meant a program could have filled the record with junk entries until the genuine choices were impossible to find — and those records are the evidence of consent. It now accepts a limited number of requests from any one connection.
    • The responses from your account area, including the pages showing your charges and any payment you are being asked to confirm, were not marked as uncacheable. A shared network cache in between could in principle have kept a copy. They are now explicitly marked so they are never stored by anything along the way.
    • There is now a single command that runs the whole payment system's checks end to end — every scripted payment test, the reconciliation between what the payment provider says and what our own records say, and a written report of the result. It refuses to run at all if it is not certain it is pointed at the test environment, so it can never touch live money by accident.
    • Two failure messages repeated the database's own internal wording back to the browser, which can disclose table and constraint names. They now return a plain sentence instead. The requests still fail — a change that could not be saved is never reported as a success — but nothing internal is leaked while saying so.
    • A test that was meant to prove the request limits were in place passed for the wrong reason: it checked that a limit was reachable, which a duplicated or misplaced limit satisfied just as well as a correct one. It now checks that every route in the account area is either genuinely limited or has a written, checked explanation of why a per-account limit does not apply to it — which is what makes the coverage real rather than assumed.
    • Two scheduled-payment scripts were testing behaviour that the system had deliberately moved away from, so they would have reported a problem that was actually a correct design. They now test the behaviour that is actually in force, and one of them no longer relies on an account that may or may not exist.
  13. v9.20.0

    Nothing here was being checked automatically — so the checks now check themselves

    • The check that runs before anything is published was quietly doing less than it appeared to. It did check the code, but three of the rules it is meant to enforce — that every part of the site is registered in the test inventory, that the review-findings log stays accurate, and that no file was published while the files it imports were left behind — only ran under a flag almost nobody used. Those three now run on every push, so the green light means what it says. Separately, a command added to manage that check was itself pointing at a file the system ignores, and reporting success while doing nothing; it now resolves the file the system actually uses, and refuses to report success unless it is genuinely in place.
    • When a new copy of the app is created from the repository, it now arrives with a documented list of the settings it expects. Without it, a new setup had no way to know what to configure, and the same missing file meant the test inventory could never agree with itself — reporting a discrepancy that no change could resolve.
    • Three of the four checks that were supposed to run before a push were, in practice, only reachable through a flag almost nobody used. The site-wide test inventory, the review-findings log, and the check for a file committed without the files it imports are now part of the standard bar. A verdict that reads as "ready to ship" now means the same thing every time it says it.
    • The public directory pages were taking between half a second and one and a half seconds to load, and the reason was not the work on the page: each one was asking the database several questions one after another instead of together, and nothing was cached. The two independent lookups on the business directory now run as a pair, cutting a third off its load time. A check now pins that shape, so the slow arrangement cannot quietly come back.
    • The status page asked the database once per monitored job — forty-eight separate round trips for one page view. It is now a single query, a real change on a page that is meant to be the fastest thing you can open when something is wrong.
    • A group of sales recorded in early September could sit in escrow forever: they had been logged as waiting for payment, but the payment never happened, so no payout could ever be triggered. They inflated the "owed to creators" figure indefinitely. A scheduled sweep now closes out any such record automatically once it is more than a week old, and one such record has already been cleared. Separately, the background page used to miscount money still waiting to be paid out because of this.
    • The database's own record of which changes had been applied to it listed fourteen changes while a hundred and fifty-three had actually been applied. Anyone who ran the standard "reset my local database" command would have been reasoning from a version of the past that was badly out of date — and that command is destructive. The record has been rebuilt from the actual repository and now stays current automatically.
    • A test-timing fault that made the suite's results depend on how busy the machine was has been removed. It had already caused three separate runs to fail for no real reason, and one test in particular was relying on a wait roughly forty times shorter than every other test beside it.
  14. v9.19.0

    Four background jobs were doing each other's work, four times an hour

    • Four scheduled jobs were each running every background task on the platform rather than just their own. A reconciliation meant to run once a night, and a charge-recovery job meant to run once a month, were both running every hour. Nothing was charged twice — every job is safe to repeat — but at scale it is thousands of unnecessary calls a day. Each now runs only its own work.
    • Seven jobs were running in production with nobody watching them, including the sweep that returns a business's unspent campaign money after a week of silence. If it had stopped working, nothing would have said so. All seven are now monitored, and a new check fails if a running job ever drops off the list or a listed job is not actually scheduled.
  15. v9.18.2

    Local development reliability: the dev server can no longer start against the wrong app

    • The development server now refuses to start in three situations that previously failed silently or misleadingly — from the wrong folder, without the environment settings it needs, or while a different copy of the app is holding the port. Each now states the cause and the exact fix, instead of leaving you with a generic configuration error and a blank page.
    • One command reports the state of a development machine: environment settings, free disk space, which servers are running and from which folder, and whether the live database still matches the migrations in the repository. It is silent when everything is healthy and exits with a non-zero status when something will actually bite you.
    • The end-to-end test suite now confirms it is pointed at this application before it begins, so a stale copy left running on the same port can no longer produce an entirely passing test run against the wrong software.
  16. v9.18.1

    Every line of the AI batch is now proven by tests

    • Test hardening release — no behaviour changes. The AI integration page, key panel, AI switch, the platform's single AI call gate and the Intelligence layout now sit at 100% line, branch and function coverage (62 tests), including the anonymous-visitor paths that redirect to login. Combined with the admin pages from the previous release, every line the team touched this week is now executed by a passing test.
    • Two internal type-annotation cleanups that make coverage reporting exact (same behaviour, simpler shapes for the test runner to reason about).
  17. v9.18.0

    The AI is one switch, keys actually save, and audit logs become append-only

    • The built-in AI is now ONE integration — not an integrations hub — with a single switch: on by default, and turning it off pauses every AI feature (smart search, scoring, drafting, scripts, the pitch coach) at the platform's single AI call chokepoint. The switch lives on the AI integration page alongside the key that powers it.
    • Connecting an AI key actually works now: the key panel was stuck on "Loading keys…" forever (an empty list read as "still loading"), saved keys never rendered (the list read from a state nothing updated), and the save button was permanently disabled with a spinner the moment the input opened. All three fixed and pinned by tests.
    • Every Intelligence page now sits in the dashboard shell — back button in the top bar and content that fits the screen (the whole Intelligence area used to render bare, with neither).
    • Audit logs are append-only at the database: migration 145 blocks UPDATE, DELETE and TRUNCATE on admin_audit_logs for every role including service_role, so the immutability the audit page claims is now enforced by Postgres itself.
    • The Intelligence hub is role-aware: business-only tools (Briefs) no longer appear on a creator's dashboard.
    • Admin money triage: the conversions CreatorView showed every row as "£0.00" platform cut and "no charge (wallet/grouped)" regardless of truth (columns were under-selected), and the finances totals silently capped at 10,000 rows per type while claiming exactness — both fixed, with the touched admin pages measured at 100% line+branch coverage.
    • Audit-log search silently returned zero rows for any term containing quotes or parentheses (the PostgREST filter string broke); the client-crashes spike card said "this hour window" for a 7-day aggregation; dispute fees rendered as a raw type string.
  18. v9.17.0

    Pitch coach, live Spyder status and brief funnels — with a money-integrity pass

    • AI pitch coach: before a creator submits a pitch on a brief, one click reviews the draft against that brief on the AI key they connected — concrete, actionable feedback on fit and clarity. Nothing is charged, reserved or released anywhere in the pitch flow.
    • Brief analytics for businesses: every brief now shows its funnel — share-page views, pitches received, approvals, and how long decisions took — so a quiet brief is easy to tell from an under-priced one.
    • Spyder polling you can trust: the Spyder page shows a live status badge with the last successful poll time, and a failed poll fires an admin alert immediately — silent data staleness is no longer possible.
    • Research and Integrations hubs: one page for the Intelligence suite, one for everything that plugs in (AI keys, the ad-saver extension, social accounts, Google Ads) — plus brief templates to start from.
    • Discovery saved searches with new-ad alerts, view counts on shared boards and briefs, AI brief drafting, and pitch decision emails.
    • Money-integrity pass (migrations 141–144): per-campaign order-id uniqueness, atomic webhook retry accounting, subscription paused status, share-view counting and saved-search tables. Ledger display math is decimal-safe with campaign-authority currency, and every unbounded background read is now paged.
    • The rating sort in Discovery and the swipe file silently ignored its null-ordering option, so unrated items sorted first — unrated now sorts last in both directions.
    • How-it-works completed a full word audit against the code: 13 wrong or over-broad claims corrected (charging modes, 3-D Secure semantics, the webhook-signature description, AI-scoring dimensions, fee wording and more), each now pinned by tests so drift fails CI.
    • Vercel function storage slimmed: sharp and ffmpeg are bundled only into the routes that use them (the tracer had put ~2.3 GB of binaries into all 123 functions per deploy).
  19. v9.16.0

    The intelligence suite grows up: AI search, AI scoring, public share links, and briefs you can pitch on

    • Discovery gets a brain: with an AI key connected (Settings → AI keys), “Smart search” finds ads by meaning instead of keywords — “playful eco-friendly skincare for Gen Z” surfaces the right creatives even when no word matches — and a one-click AI score grades any ad's hook, clarity and conversion potential with written reasoning. No key connected? A friendly connect-your-key card takes you straight there, and plain search keeps working exactly as before. The platform pays nothing per call — every AI call runs on your own key.
    • Share your research outside the dashboard: swipe boards and briefs now have public read-only pages at /b/<token>. “Share” copies the link; anyone with it sees the board's ads (brand, copy, platform, first-seen) or the brief's sections — no login, nothing editable, nothing personal. Unshare from the dashboard and the link stops working instantly.
    • Briefs are now two-sided: creators browse open briefs and pitch their deliverable plan against one (withdrawing is theirs to do while a pitch is pending); business owners review pitches in their inbox and approve or reject with a note. Approving a pitch creates a pending application on the brief's linked campaign — the business then accepts it through the exact same flow as any other collaborator, where the existing payment authorisation and deliverable slots live. No money moves at pitch time.
    • Brief owners can link a brief to one of their campaigns when creating or editing it — that link is what turns an approved pitch into a real collaboration.
    • The public changelog page and RSS feed had not caught up with the intelligence-suite release (Phases 0–2) — the backfilled v9.15.1 note below restores the record to completeness.
  20. v9.15.1

    Free ad-intelligence suite: BYOK AI keys, swipe file + extension, and the Discovery library

    • Backfilled entry: this release shipped 2026-09-20 (commit 0d63d45) but was only announced in the download changelog — the public page missed it, so it is recorded here for completeness.
    • BYOK AI keys (Settings → AI keys): connect OpenAI, Anthropic, Google or Deepgram; keys are validated live, stored AES-256-GCM encrypted, write-only (only a masked hint ever returns), and power every AI feature at zero platform cost.
    • Swipe File: save ads with source URL, platform, format, copy and first/last-seen dates; boards with share-token public read; filters plus the signature longest-running sort. A zero-dependency Chrome extension saves ads from the Meta, TikTok, LinkedIn and Google ad libraries.
    • Discovery: opt-in community ad library — publish swipe items to the pool (no personal data), public search + platform filter + longest-running sort.
  21. v9.15.0

    You never pay a Stripe fee — businesses do, with itemised statements and 48h notice

    • Zero-cost platform guarantee completed: Stripe's dispute (chargeback) fees — roughly £15–£20 the moment a cardholder opens a dispute, win or lose — are now recorded on the affected order and recharged to the business at cost on the same monthly statement as processing costs. The platform adds nothing and absorbs nothing.
    • Itemised statement PDFs: every monthly processing-cost statement now downloads as a PDF listing each order with the exact Stripe cost it carries, so a business can reconcile the charge line by line (Dashboard → Payments → PDF).
    • 48-hour pre-charge notice: on the 1st of each month, every affected business receives an email and dashboard notification stating the exact amount that will be charged on the 3rd — what it covers, why, and where the itemised statement lives.
    • The Terms now spell out the two fee facts that were implicit: dispute fees are recharged at cost (they apply even when a merchant wins a dispute), and Stripe's original processing fee is not returned when an order is refunded — those costs stay payable by the business under the same at-cost pass-through.
    • Tracking setup is now pixel-only: the business Tracking page leads with the one-line paste-in pixel (no extension, no desktop app), with the checklist, settings and landing copy updated to match. The extension and desktop-tracker code is kept but hidden until re-enabled.
    • Backfilled record (added 2026-09-22, missed when this release shipped): the minimum platform fee became £10.00-equivalent with this release — max(10% of the order, £10.00 / $12.50 / €11.50) — per the owner decision of 2026-09-16.
  22. v9.14.0

    One fee for everyone, compliance follow-through, and guides built to be found

    • One fee on every plan: the platform fee is 10% of the order with a flat 10% (no minimum) that covers card processing on small jobs (£10.00 / $12.50 / €11.50 — billing is always in pounds sterling). The paid-plan half-minimum discount has been removed, so the same 10% now applies whatever plan you're on. [Superseded 2026-09-22: the model now carries a £10.00-equivalent minimum — max(10% of the order, £10.00 / $12.50 / €11.50); the “no minimum” wording above is the earlier flat era. See v9.15.0.]
    • Compliance follow-through: if a creator's submitted post still has no #ad attestation 48 hours after their reminder, the reviewing business now receives an escalation email about that submission — so a missing label is caught before approval rather than after it.
    • Rejections that don't dead-end: businesses reject a deliverable with a written reason (the creator sees exactly what to fix), the tracking link is revoked automatically, and the creator can reset that deliverable and resubmit without losing their place in the campaign.
    • Every guide now ends with real questions and answers — 13 guides, three Q&As each — alongside article and breadcrumb structured data, so answers like “how and when do I get paid?” and “when must I label a post?” can surface directly in search results.
    • A searchable glossary of the platform's vocabulary (tracking link, hold, platform fee, tiers, dispute SLA and more), plus a guides index that links all 13 guides and the glossary — no page left unreachable.
    • The business product tour now walks through the real campaign wizard, pre-filling a complete example campaign so you can see every field, payment type and minimum in context. Nothing is created until you press Publish yourself.
    • Fee copy corrected platform-wide: the minimum platform fee is £5.00-equivalent (it had been documented as £2 in places). Every page, guide, email, dashboard and the fee calculator now states the same figure the platform actually charges. [Superseded 2026-09-22: the minimum platform fee later moved to its current £10.00-equivalent floor. See v9.15.0.]
    • The how-it-works money-flow diagram, the earnings and payouts screens, and the fee calculator once again agree with the payout maths the platform runs on every order.
  23. v9.13.0

    #ad enforcement, consent evidence, and a compliance dashboard

    • Ad-disclosure enforcement: affiliate and hybrid submissions now require the creator to attest their post will clearly show #ad (or “Ad”) before anyone expands or clicks — the Submit button stays locked until they tick it, the API rejects unattested submissions outright, and businesses see the attestation with its timestamp when approving.
    • #ad compliance dashboard for businesses: a per-post view of which creator posts carry the attestation and which don't, with an overall compliance rate. The rate is free for every plan; the per-post detail (creator, post link, attested-at) unlocks on Growth and Enterprise.
    • Platform-aware #ad caption templates (TikTok, YouTube, Instagram) with one-click copy next to every live affiliate link, so the label survives each platform's “more” fold. A reminder also arrives by email the moment a tracking link goes live.
    • Cookie choices you can actually change: a “Cookie choices” link in the footer reopens the consent banner on every page, so consent can be withdrawn or updated at any time without clearing site data.
    • ICO-ready consent evidence: every banner decision (accept-all or saved choices, including anonymous visitors) is recorded with one-way hashed identifiers. Admins can review the log, export it as CSV, and generate a cover memo PDF (evidence window, decision counts, retention policy) — a two-click answer to an audit or subject-access request.
    • Creator guide and privacy policy brought up to date: the enforced attestation and the withdrawal flow are documented step-by-step, and the privacy policy now enumerates every cookie and storage key, the consent-gated telemetry session ID, and how long each log is kept.
    • A gentle nudge on the creator dashboard if any submitted post is missing its attestation (legacy submissions only — new ones can't skip it).
    • Fixed a pre-existing permissions quirk that silently skipped the “campaign paused” block on creator submissions — paused campaigns now reliably refuse new submissions.
    • Telemetry no longer writes a session ID to browser storage before an analytics choice is made: declining analytics now means zero storage writes and zero beacons.
    • Creators' accounting and GDPR data exports now include campaign names for every linked campaign, including ended or unlisted ones that were previously blank.
    • The creator guide's payout minimum said $25; the platform bills in GBP — corrected to £25.
  24. v9.12.0

    Clearer pricing, a bigger premium tier, and a safer money path

    • Repriced plans: Business Enterprise is now £7.99/mo and Creator Premium £9.99/mo. US and EU visitors see approximate $/€ conversions on pricing pages (billing stays in £).
    • Add-on line items are gone from the UI — plans are flat monthly prices again.
    • Creator tiers re-laddered to 100k/1M/10M+ followers (small = fixed, moderate = +affiliate, big = +hybrid), applied consistently from onboarding to eligibility.
    • Campaign types are now plan-gated: businesses get affiliate on Growth and hybrid on Enterprise; creators get affiliate on Pro and hybrid on Premium. Premium creators can run up to 20 campaigns at once and 20 per rolling week.
    • 30-day free trials on Enterprise and Premium are now available with no card — verify your email to start, and any mid-trial upgrade credits the remaining days onto your subscription.
    • Team seats: Growth stays owner-only and Enterprise seats 3; invitee acceptance and member access were fixed (a policy recursion had been hiding the roster).
  25. v9.11.0

    Dispute voice for creators, PDF receipts, template trends

    • Creators can now raise a dispute on refunds that hit their earnings — with evidence upload, a 5/day limit, and admin review within 48 hours. No more one-sided reversals.
    • Every approved refund generates a PDF receipt (refund + fee breakdown) that businesses can download from Payments for their records.
    • Template analytics: a 12-week downloads-vs-campaigns chart with a conversion rate shows which templates actually turn into work.
    • Platform: fixed a production Stripe key mismatch that silently blocked per-conversion charging.
  26. v9.10.0

    Small refunds approve themselves; creators see every dispute

    • Auto-approval: refund requests on orders of £25 or under execute immediately with the full fee policy — no admin wait. The audit trail marks them automatic.
    • Creator transparency: disputes and refund requests that touch a creator's conversions now appear on their Earnings page with status and outcome — money is never reversed silently.
    • Template analytics: each template card now shows how many campaigns were actually created from it, closing the downloads → campaigns loop.
  27. v9.9.0

    Refunds & disputes end-to-end, template management, custom plan builder

    • Refund requests: businesses can request a refund on any charged conversion from Payments. The initiator pays the processing fee (10% of the order, min £2.50, capped at £50); the creator's held earnings reverse proportionally; approval is admin-reviewed and audit logged.
    • Refund requests appear in the admin SLA Command Center with one-click approve/reject and the fee policy spelled out before confirming.
    • Campaign templates are fully manageable: edit title/description, publish or unpublish from the marketplace, and delete — and the "Save as template" option in the wizard now actually saves (a silent failure since launch).
    • Plan builder: tick only the capabilities you need on the pricing page, add extra campaign slots, and see the price update live.
    • 2FA hardening: sign-in no longer demands a code from accounts that don't have one enrolled (admin accounts keep their enforced second factor).
    • Under the hood: grouped-campaign split resolution reads the right applications table (a bug that would have zero-weighted every grouped split).
  28. v9.8.0

    Trust fixes everywhere + grouped charging behind the flag

    • Verification emails deliver again: the auth sender moved off a yahoo.com mailbox (strict DMARC — providers silently dropped the mail) to no-reply@adswish.co.uk on the platform's own aligned domain.
    • Getting Started no longer shows a false "Stripe connected": creator payout status now uses the maintained readiness flag, and businesses are guided to the saved-card flow instead of being minted an unusable Connect account.
    • Role safety: the middleware now bounces cross-role dashboard access (a creator can never open a business page and vice versa), and the 2FA screen has an unmissable way back to the site.
    • Grouped charging (new campaigns only, by choice at creation): pre-fund a campaign wallet, pick a split rule (equal / weighted / custom / decide-later) with a live per-creator payout simulator, and sales draw from the pot chronologically — if sales outrun the pot the last sale is partially paid and audited, never clawed back, and the campaign pauses at £0 until you extend. Per-sale charging stays the default and is untouched.
    • Transparency: the status page now shows whether incident chat-alerting is configured, and businesses see a 48-hour countdown timer on every open dispute from their Payments page.
  29. v9.7.0

    Fix-forward via canary: the prescribed path back to production after an incident

    • New "Fix Forward via Canary" workflow: build the fix on any branch ahead of main, run it from the Actions menu, and the fix is validated on an ISOLATED deployment (smoke + read-only E2E, production domains untouched) before main is fast-forwarded and production is promoted. A failure at any stage leaves main untouched.
    • Auto-rollback incident issues now contain step-by-step fix-forward instructions, and the workflow can comment on and close the linked incident issue automatically when the fix ships (pass the issue number when dispatching).
    • The /status Release pipeline card now shows which commit is on staging vs main, whether the staging commit has passed validation, and their relationship (nothing pending / validating / ready to promote) — backed by a dedicated main-verification event recorded by every successful post-deploy smoke check.
    • New reusable scripts: smoke-url.mjs (smoke-check any URL) and a hardened check-canary.mjs that validates isolated deployments for both the staging canary and fix-forward preview paths.
  30. v9.6.1

    Canary pipeline hardening from a live drill

    • The canary pipeline was exercised end-to-end for real, twice: a staging commit was smoke-checked and E2E-validated on its isolated branch alias, then promoted — production fast-forwarded, the new build verified to hold the domains, and the live smoke check passed.
    • Fixed a pipeline-starvation bug the drill exposed: a canary run sharing the production concurrency group was auto-cancelled whenever a newer main push queued. Staging now has its own group; promotion still serializes with production.
    • Fixed canary build discovery (Vercel builds staging pushes with target=production but never assigns prod domains) and added a hard safety check that a canary must never hold the production domains.
    • Promotion no longer trusts Vercel's GitHub push webhook (observed dropping a deploy): CI triggers the build itself, then verifies promotion and smoke-checks the live site before declaring success.
    • The protection-bypass secret used for canary/preview validation was found empty (from an interrupted edit) and regenerated via the Vercel API — verified by proving the header flips an SSO 302 into a 200.
  31. v9.6.0

    Release pipeline transparency: live canary state and incident log on the status page

    • A new 'Release pipeline' card on the status page shows exactly what the release automation did — canary smoke checks, read-only E2E validation, promotions to production, and incident alerts — each with its commit, outcome, timestamp, and a link to the pipeline run that produced it.
    • The canary promotion is now webhook-proof: CI triggers the Vercel build itself instead of relying on GitHub's push webhook (which was observed dropping a deploy), then verifies the promoted release holds the production domains and passes a live smoke check before declaring the release done.
    • Incident alerts gained a built-in test: a one-click 'Test Incident Alert' workflow in GitHub Actions sends a real message through your Slack/Discord webhook and fails loudly if nothing arrives, so you can verify your phone receives production incidents before you need it.
  32. v9.5.0

    Canary releases and incident alerts straight to your phone

    • Canary release pipeline: push to the `staging` branch and it deploys to an isolated canary URL (the branch's own alias — production domains untouched), gets smoke-checked plus the full read-only E2E suite, and only when everything is green is `main` fast-forwarded to that exact commit. Production always deploys code that already passed every check; a failing canary aborts promotion and production keeps serving the previous release.
    • Incident alerts to Slack or Discord: auto-rollback events, failed canaries, and recovery notices now reach your phone via webhook — add INCIDENT_SLACK_WEBHOOK or INCIDENT_DISCORD_WEBHOOK as a repo secret and every production incident arrives as a push notification instead of only a GitHub issue.
    • Recovery notices that close the loop: when a post-release smoke check passes while an incident is still open, CI comments on the incident issue, closes it, and pings the channel — healthy deploys with no open incident stay silent, so no notification spam.
    • A read-only Playwright suite (`canary` project) now runs against any live deployment URL via E2E_BASE_URL — including through Vercel's SSO protection bypass — with zero database writes, so release validation never touches customer data.
  33. v9.4.0

    Manual rollback button, preview-deploy validation, and a live-proven auto-rollback

    • Manual Rollback: a one-click GitHub Actions button (Actions → Manual Rollback → Run workflow) that restores production to the previous release, a specific commit, or an exact deployment — it lists the last 10 releases in-run and verifies the restored site before finishing. No terminal required.
    • Preview-deploy validation: every pull request now gets its Vercel preview deployment smoke-checked (key routes + changelog content, through Vercel's SSO protection bypass) before it can reach main, so risky changes are validated on a real preview URL first.
    • Fixed a smoke-check race found during a live fire drill: the post-deploy check could pass against the previous release before the new deploy was promoted. It now waits for this commit's deployment to hold the production domains before validating.
    • The auto-rollback was exercised against production for real: an intentionally broken release was deployed, the smoke check failed it, production was automatically rolled back to the previous release within minutes, and the fix-forward recovered cleanly — all recorded in an auto-opened incident issue.
    • Fixed the cron-health alert dedupe window using wall-clock time instead of the sweep's own timestamp (production sweeps unaffected; explicit-timestamp sweeps and tests were).
  34. v9.3.0

    Production auto-rollback: a broken release now reverts itself

    • If the post-deploy smoke check fails after a push to main, CI automatically re-points adswish.co.uk / www.adswish.co.uk at the previous READY release and opens an incident issue with the run link — a broken deploy reverts itself within minutes instead of staying live until someone notices. The next healthy deploy re-claims the domains automatically.
    • This delivers the guarantee of GitHub branch protection (nothing broken stays in production) on the repo's current GitHub plan, while keeping push-to-main deploys fast — no branch/PR detour required.
  35. v9.2.0

    Cron health alerting, scheduling repairs, and deploy safety net

    • The /status 'Scheduled jobs registry' is now actionable: an automated cron-health sweep checks every supervised background job against its expected cadence and alerts the administrators when a job goes stale, has never run, or keeps failing — via in-app notification, email, and chat webhooks. Alerts fire on transition and repeat at most every 12 hours while a job stays unhealthy.
    • Fixed a real scheduling gap the registry exposed: the badge-refresh job had no schedule at all (it only ever ran from a manual trigger) — it now runs every 6 hours.
    • Repaired the cron delivery pipeline: pg_cron was POSTing to a dead deployment URL and the cron secret had drifted out of sync with production, so scheduled jobs were silently not running. The base URL now points at the live domain and the secret is synced; job runs are being recorded again.
    • Deploy safety net: a post-deploy smoke check sweeps key routes (including the changelog's version card) on every release, CI runs the full verification gate on push with a post-deploy smoke job on main, and the public status page lists every supervised cron job with its live schedule state.
    • Production email config (SMTP) is now set so admin alerts and transactional email deliver for real instead of falling back to local file writes.
    • Fixed a hydration mismatch in session-timeout settings (server/client class difference) and a console error from the browser-support detection script — both found by live verification.
  36. v9.1.0

    Collapsible sidebar with command palette, focused settings navigation, and chrome polish

    • The dashboard sidebar is now collapsible: a 64px icon-only 'peek' rail (nav icons with native tooltips) replaces the full sidebar. Drag the edge past the minimum to snap it fully in or out, click the arrow or press ⌘B / Ctrl+B to toggle, double-click the edge to reset, and resize with the arrows or Home/End keys as before.
    • Sidebar state is remembered per dashboard section. Settings, Discover, Messages, and Analytics open collapsed to the icon rail for a focused / larger-surface view; opening one is remembered for the next visit.
    • A ⌘K / Ctrl+K command palette opens any dashboard section by typing, toggles the sidebar (⌘B), goes back (⌘[), shows a RECENT row of your last pages, and offers a 'Restore sidebar defaults' reset.
    • Settings now deep-links: clicking Settings in the sidebar returns you to the last settings subsection you visited instead of always landing on the overview.
    • The Settings local nav and the main sidebar are mutually exclusive — the page's own sub-nav appears when the sidebar is collapsed and steps aside when it is open.
    • The active section in the peek rail gets a small pulsing accent dot (reduced-motion aware), and a subtle shadow follows the sidebar while it is dragged.
    • Typing a letter while the sidebar is collapsed focuses the matching section (press again to cycle).
    • Shared chrome polished to match the curated design language: 12px corner radius scale, press and shadow cues on primary buttons, and an ink pill for the active nav item.
    • Fixed a hydration error: badges rendered as a <div> inside <p> (the Getting Started list and earnings activity feed) — they now render as a <span>, visually identical but valid HTML.
    • Removed every lint warning (6 raw <img> to next/image, unstable useMemo dependencies, a missing effect dependency) — the codebase is now at 0 errors, 0 warnings.
  37. v9.0.0

    Automation and ops: creator digests, ROI one-pagers, dispute evidence, card health, and audit-log search

    • Weekly creator digest email now includes a per-day payout forecast, so creators can see exactly when their held money clears.
    • Business 'campaign ROI' one-pager PDF export — a single-page summary of a campaign's performance that can be filed or shared, now attached to the weekly business digest email.
    • Auto-generated dispute evidence bundles: the dispute record, the linked conversion's money timeline, and campaign/deliverable context assembled into one chronological bundle for admins.
    • Stripe balance reconciliation check (database vs Stripe nightly) and refund-spike detection surfaced in the weekly anomaly digest.
    • Saved-charge-failure 'card health' badge on business profiles, with a dying-card nudge email and notification before the 3-failure auto-pause (deduped per campaign).
    • Admin 'impersonate view' read-only mode for support, now with a notes trail stored as audited rows so every access and note is on the record.
    • Weekly admin P&L email: fees, Stripe processing fees, net, payouts, and refunds in one place.
    • ROI-driven campaign template suggestions ('Suggested from your results') on the Templates page with one-click wizard prefill from your best real setups.
    • Creator availability calendar and away auto-decline: while a creator is unavailable, a business invite is politely rejected with the reason.
    • Budget pacing alerts: the cron emails and notifies a business when a campaign crosses 80% of its cap.
    • Dispute SLA timer shown in the campaign chat banner — urgency-coloured, hours remaining until the 72-hour auto-resolution.
    • Creator payout-forecast email and per-day clear schedule appended to the creator digest.
    • Fixed the audit-log free-text search: it queried the uuid target_entity_id with ilike, which PostgREST rejects — every search on the live app returned zero rows. Now handles full-uuid terms and the affected route is covered by E2E.
    • Fixed the support-view audit constraint (migration 093) that never included the support_view action type, so every support-view access had silently failed to audit since launch.
    • Fixed a chat hydration mismatch where message timestamps used the ambient locale (server Node-ICU differs from the browser) — pinned to en-GB.
  38. v8.2.0

    Payout forecast, onboarding drop-off funnel, and SLA enforcement alerts

    • Payout forecast for creators: the earnings page now shows exactly when held money clears — derived from each pending conversion's 7-day escrow expiry, with a plain-English explanation of the escrow + weekly payout cycle.
    • Onboarding drop-off funnel: a daily snapshot tracks signups through profile → onboarding complete → Stripe connected, and the new admin funnel card shows each step's share and step-over-step conversion with drop-off colour coding, so we can see precisely where signups abandon.
    • SLA enforcement is now visible: at the 72-hour auto-resolution moment the platform fires a Slack/Discord chat alert (the 48-hour admin escalation already existed), so every enforcement action is on the record.
    • Account cleanup completed: the confirmed list of stale test/demo accounts was removed (with backups), leaving a clean production user base.
  39. v8.1.0

    Session cookies, adaptive settings navigation, first-login tour, and safer first charges

    • Log out on browser close: every auth cookie is now a browser-session cookie across server, middleware, and browser clients, with a token refresh on dashboard load — closing the browser ends the session.
    • Log out everywhere: a new Security settings card revokes every session across all devices (Supabase global sign-out), for when a device is lost or a session is compromised.
    • Settings became a sectioned page with its own sidebar (Security, Sessions, Notifications, Data export, and more), and the dashboard sidebar now expands context-aware sub-navigation for the active section.
    • First-login spotlight tour: role-specific steps on first sign-in, persisted per account, replayable anytime from Settings.
    • Safer first charges: a business's first conversion charge from a new card now enters the 3D Secure queue instead of failing, then completes automatically once authentication finishes.
    • Tracker downloads now come from the public GitHub repository with verified installer assets; a new auto-create button sets up the UptimeRobot monitor from the Tracking page; the Chrome extension block is labelled 'Coming soon'.
    • DNS verification diagnostics now report the exact DNS records found versus expected, making failed domain checks actionable.
    • Country & currency settings: pick your country in onboarding or Settings; amounts display in your local currency symbol while the ledger stays in GBP.
  40. v8.0.0

    Profitability engine: minimum platform fee, full cash refunds with refund-processing fee, and true-net measurement

    • Minimum platform fee: the platform's take is now max(10%, £2-equivalent) per transaction, so small jobs can never price below Stripe's processing cost. Multi-slot fixed campaigns prorate the fee fairly per slot. [Superseded 2026-09-22: the floor later moved to £5.00-equivalent and then to its current £10.00-equivalent. See v9.15.0.]
    • Minimum order sizes: fixed and affiliate/hybrid campaigns require a £25-equivalent minimum, and tracked conversions a £20-equivalent minimum — enforced in the API and the campaign wizard.
    • Full cash refunds: refunds return 100% of the gross in cash (never credits), granted through the refund process.
    • Refund-processing fee: 10% of gross (min £2.50, cap £50) is charged to the party who caused the refund — the business's saved card for business-caused refunds, the creator's held cut or a payout hold for creator-caused refunds. Chargebacks are exempt and never fee'd.
    • True-net measurement: the charge.succeeded webhook records Stripe's actual processing fee into the ledger, and a new invariant check alerts admins if any charged conversion nets below zero after fees.
    • Payout holds: post-release recoveries (creator-caused refunds and chargeback debts) can hold a creator's future payouts until the admin clears the recovery.
    • New /admin/finances ledger view: per-conversion hold/release/refund/fee timelines plus a net-margin rollup, and the /status page now monitors fee-capture webhook health.
    • Updated Terms and marketing pages to match the enforced fee, minimums, refund, and chargeback model.
  41. v7.1.0

    Messages redesign, universal business verification, financial-grade analytics, and status history

    • Messages redesigned into a proper inbox: a conversation list on the left with a single selected chat panel (instead of every campaign's chat stacked on one page). Completed chats get a clear Done treatment with show/hide-completed controls and hash deep links (#c-campaignId) so a conversation can be linked directly.
    • Universal business verification: businesses without a website can now verify ownership through their Apple App Store listing (official Apple lookup API), Google Play listing, or any public page they control (Linktree, Notion, Carrd, GitHub org, social profile) — alongside the existing DNS TXT and homepage meta-tag methods. Which method verified the brand is recorded in the new verified_via field (migration 079).
    • Financial-grade analytics for both roles: expanded KPI strips (ROAS, AOV, EPC, approval rate), a daily revenue-vs-cost chart, campaign-level performance chart, a detailed daily-performance table, and CSV export for the whole dataset. Charts now render correctly even when there is no data yet.
    • Payment methods management: businesses can list saved cards, set a default, and remove cards from the Payments page (Stripe customer API, no card data ever touches Adswish servers).
    • Public status page now shows availability history: 24h and 7-day uptime percentages computed from the platform's own health-check history, plus the last incident with its recovery state.
    • Resizable dashboard sidebar: drag the right edge (or use arrow keys) to widen or narrow it; the width persists per browser. Double-click resets it.
    • Browser-support notice: browsers below the Next.js 16 + Tailwind v4 floor (Chrome/Edge/Firefox 111+, Safari 16.4+) now see a clear 'switch to Chrome' banner with a download link instead of a silently broken page.
    • Business profiles now show substance: campaign history and recent reviews are rendered on the profile page, and the profile shares the same verification card as onboarding.
    • Getting Started and Tracking pages now guide app-only businesses: any public URL (app listing, Linktree, API endpoint) can be monitored with UptimeRobot, and presence verification accepts store listings and link pages.
    • Removed the unused Resend integration everywhere (hub catalog, subprocessor list, dependency, setup script): transactional email is Keplars + SMTP only.
    • Fixed the stale team-invite email comment that still referenced Resend.
  42. v7.0.0

    Resilient 60s heartbeat (MV3 alarms), in-house health history, and dashboard-wide disconnect banner

    • The Chrome extension's 60-second heartbeat now survives service-worker suspension: a chrome.alarms watchdog (minimum 1-minute period) wakes the suspended worker and re-fires the pixel ping + /api/health probe even when no page is actively messaging the extension. Previously a quiet site could silently stop the heartbeat when Chrome suspended the MV3 service worker (~30s idle).
    • In-house health history: every /api/health evaluation is now recorded into a new inhouse_health_checks table (migration 076), so the platform's own application/database health has the same outage/recovery timeline as the UptimeRobot side. The write is best-effort and never affects the probe response.
    • Dashboard-wide disconnect banner for every role: when the 60-second liveness poll flags tracking as disconnected, the red banner with a direct link to the fix-it checklist now appears on every dashboard page for creators as well as businesses (previously business-only).
    • Desktop tracker update flow completed: 'Check for updates…' now reports 'You're on the latest version' via tray balloon and an in-app update-status message when no update exists, alongside the existing download → restart-to-install flow.
    • Chapter 4 — How To Scale guide page added (guides/businesses/scaling): templates, budget caps, Google Ads amplification, blended analytics, and team seats. The landing page's Chapter 4 card previously linked to the How-it-works page because this page didn't exist.
    • Legal and marketing copy corrected: Terms of Service and the How-it-works hold-period step now state the uniform 7-day escrow hold for all creators (plan-based 7/5/3-day tiering was removed in v6.0.0), and the Plans page no longer implies faster payouts on paid tiers.
    • Fixed the extension heartbeat silently dying on quiet sites: MV3 service-worker suspension killed the setInterval-driven tick; the chrome.alarms watchdog now re-arms it.
    • Fixed the Chapter 4 landing-page card pointing at /how-it-works instead of a real guide page.
    • Fixed stale plan-based hold wording in Terms of Service §3 and the How-it-works payment flow.
  43. v6.1.0

    60-second tracking liveness everywhere, Getting Started auto-hide, Keplars email, and database hardening

    • 60-second liveness checks added everywhere alongside the existing 24h checks: the desktop tracker and Chrome extension now fire the pixel heartbeat and an /api/health uptime probe together every 60s, and the Tracking page polls status immediately on load and then every 60s — the verification dot reacts within one heartbeat cycle when the tracker or uptime monitor dies.
    • Getting Started page now auto-hides from the sidebar when every task is done and tracking is connected, and pops back automatically when a task is pending or tracking went disconnected.
    • Dashboard-wide tracking banner: when the 60-second liveness poll flags tracking as disconnected, every dashboard page shows a red banner with a direct link to the fix-it checklist.
    • Email delivery moved to Keplars: transactional email (checkout receipts, subscription changes, payouts, invites, digests) now goes out via the Keplars REST API when KEPLARS_API_KEY is configured, with automatic fallback to the SMTP relay and a local dev file — plus new branded checkout, subscription, and payout email templates.
    • Desktop tracker uptime check: every 60s tick now verifies site health (/api/health) in addition to the pixel ping, and the tracker UI flags the system as disconnected if either fails.
    • Closed a real data leak: app_settings (which contains the cron secret) was readable by anyone with the anonymous key; reads are now restricted to authenticated users.
    • Closed a partition RLS gap: monthly partitions of clicks_log and daily_conversion_rollups did not inherit the parent's row-level security (Postgres partitions never do), leaving them anon-readable by name. All existing partitions are now locked down, and the monthly maintenance job enables RLS on every partition it creates.
  44. v6.0.0

    Blocking GDPR consent, plan-based holds removed, token-burn fix, and enterprise UI

    • Cookie consent is now blocking site-wide: an overlay blocks all page interaction on every route until the user chooses Essential only or Accept all. Moved from the landing page to the root layout so dashboard, settings, and all authenticated pages are covered.
    • Chrome extension marketing section removed from the landing page. The desktop tracker and Chrome extension are no longer promoted as tracking options on the public site.
    • Plan-based payout holds eliminated: all conversions now use a uniform 7-day escrow hold regardless of the creator's subscription plan. Removed the Free 7d / Pro 5d / Premium 3d tiering from conversions, Stripe webhooks, fixed-campaign holds, and all marketing copy.
    • Desktop tracker v0.2.0 published to GitHub Releases with installers for all platforms: macOS Apple Silicon (arm64), macOS Intel (x64), Windows NSIS installer, and Linux AppImage. Auto-update manifests included for all three platforms.
    • Tracking page download card now shows all four platform buttons with a step-by-step install guide and copy-to-clipboard for API base URL and Business ID.
    • Payout calendar added to creator Earnings page: pending-hold conversions bucketed by release date (This week / Next 7-14 days / Later) with per-campaign creator cut and total pending release.
    • 48h dispute escalation: the SLA cron now emails every admin and drops an in-app notification when a dispute sits open past 48 hours, before the 72h auto-dismiss.
    • Weekly campaign performance digest: a new background job sends businesses a summary of clicks, conversions, and spend per creator for the past 7 days.
    • Saved cards management UI: businesses can view and update their default payment method from the Payments page.
    • Campaign creation wizard redesigned as a step-by-step process (similar to onboarding). Selecting a saved template bypasses the wizard and opens the original creation interface with all fields pre-filled.
    • Full E2E payment simulation verified end-to-end: business campaign creation, creator application, acceptance, deliverable submission with hashtag verification, business approval, tracking link generation, conversion webhook, Stripe charge (GBP), ledger hold (90/10 split), and creator earnings display.
    • Fixed a token-burn bug in the conversion webhook: the single-use jti was consumed before validating the attribution_method. An invalid payload (e.g. a typo in the method) would permanently lose the click's attribution. Now validates the method against the allowed whitelist before consuming the jti.
    • Fixed same-tab cookie consent dismiss: storage events only fire in other tabs, so the blocking overlay stayed visible after clicking Accept all in the same tab. Now dispatches a storage event locally to trigger the useSyncExternalStore subscriber immediately.
  45. v5.1.0

    Business wallet replaced with Stripe pre-authorization — no custodial risk

    • Business wallet removed: no more top-ups, cash-outs, or balance tracking. Fixed-fee campaigns now reserve funds directly on the business's saved card via Stripe pre-authorization (capture_method: manual), so Adswish never holds business money.
    • Money stays on the business's card until a deliverable is approved — capture happens at approval time, and the 90/10 split (creator 90% / platform 10%) is recorded as a pending hold exactly as before.
    • If a deliverable is rejected or the campaign never completes, the authorization is voided and the funds are released back to the business automatically.
    • 7-day maximum hold (Stripe's hard limit) is enforced by a new daily expiry job that voids stale authorizations and notifies both sides.
    • Business payments page redesigned: shows reserved-on-card holds and pre-auth history instead of a wallet balance.
    • Affiliate and hybrid flows are unchanged (charged on conversion with the same 90/10 split).
    • Verified end-to-end against a live test environment: fixed (Visa + Mastercard pre-auth → capture), affiliate, hybrid, messaging, pixel heartbeat, click logging, uptime mapping, and tracking-status checks all pass — 40/40 checks green.
    • Fixed race where an accepted fixed-fee creator could be paid without funds being committed (previously the wallet debit only happened at acceptance and the approval path never recorded creator earnings).
  46. v5.0.0

    Full landing page redesign — new hero, navigation, guides, perks, and legal pages

    • New hero section: sky-gradient scene with inflated translucent SVG lettering ("A NEW WAY TO ADVERTISE PROMOTE AND EARN FROM ADS"), design guide lines, crosshairs, and cloud wisps — replacing the previous oval/collage hero.
    • Navigation completely redesigned: floating glass pill bar with the Adswish wordmark, six nav links (Creators, Businesses, Plans, How it works, Perks, Guides), and Sign in / Sign up buttons right-aligned.
    • Navigation accent color changed from purple to blue; Download button renamed to Sign up.
    • How it works section expanded to 5 steps: added step 05 — "Business gets ads" (Custom-made adverts reach the right viewers).
    • Perks section redesigned as a side-by-side split layout: business benefits on the left, creator benefits on the right, replacing the previous horizontal carousel.
    • Guides section redesigned: four chapter cards (How To Start, How To Build, How To Sell, How To Scale) in a 2×2 grid with pixel-art illustrations, dividers, metadata, and hover lift.
    • Integrations section updated to show only new advertising integrations (Google Ads, Meta Ads, TikTok Ads, YouTube Ads, Instagram Ads, X Ads, LinkedIn Ads, Pinterest Ads, Snapchat Ads) — core services removed from the marketing grid.
    • "See how it works" button now links to the dedicated /how-it-works page instead of an on-page anchor.
    • Starburst lens-flare effect removed from the hero scene.
    • Subprocessors, Privacy Policy, and Terms of Service pages updated with latest content.
  47. v3.8.1

    Homepage Perks section redesigned as a side-by-side business and creator layout

    • Replaced the Perks carousel with a split-page layout: business benefits on the left and creator benefits on the right.
    • Preserved the Perks heading, supporting copy, and icon/badge treatment while making the two audiences visually distinct.
  48. v3.8.0

    Landing page rebranded to Adswish, dark CTA fixed, cookie banner improved

    • Landing page hero rebranded from 'tildei' to Adswish: logo, headline ("Business & Creator Ads Marketplace"), navigation (Creators, Businesses, How it works, Perks, Guides), and CTA ("Get Started Free").
    • Dark CTA section ("Ready to begin?") background fixed: was being overridden by the dot-grid CSS rule; now uses a deep navy (#0c0e16) with blue radial glow and is properly excluded from the dot-grid overlay.
    • Cookie consent banner improved: solid white background with shadow for better contrast, buttons ("Essential only" and "Accept all") now visually distinct and reliably pressable with explicit pointer-events and hover states.
    • Fixed dot-grid CSS rule applying to the dark CTA and footer sections — added :not(.dark-cta-section):not(footer) exclusions.
    • Fixed cookie banner buttons being hard to press — added solid white background, shadow, and explicit hover/focus styles.
  49. v3.7.0

    Landing page redesign, dark mode toggle, team roles, real-time analytics, and Playwright E2E

    • Landing page hero redesigned: new Cofounder-style layout with pixel-art meadow backdrop, floating status pills (Task Completed badges), and refreshed headline/CTA copy — "Adswish lets you run creator campaigns with built-in tracking."
    • Dark mode quick toggle: a sun/moon/monitor cycle button now lives in the dashboard top bar. One click cycles light → dark → system. Appearance settings persist from the existing Settings → Appearance page; the toggle is a convenience shortcut.
    • Team admin/member roles: the business_team_members table already stored admin vs member roles; the API now enforces role-based permissions (admins can manage the team, members have read-only access).
    • Real-time analytics hook: useRealtimeAnalytics() subscribes to Supabase Realtime on daily_conversion_rollups — metrics update live without polling. Reconnects on tab visibility change.
    • Playwright E2E test suite expanded: landing page tests updated for new hero, plus new tests for status page, plans, signup consent checkboxes, /reset-password, /onboarding redirects, legal pages, and 404 handling.
    • Campaign strip now shows with any active campaign count (was gated at 100+). The section uses real data from /api/v1/campaigns/count — never fabricated examples.
    • Fixed /reset-password 404: new page handles Supabase recovery tokens (code exchange, PKCE fallback, implicit grant support) then redirects to /update-password. Password reset emails now work end-to-end.
    • Fixed /onboarding/creator and /onboarding/business 404: new redirect pages read the user's onboarding_step from their profile and route to the correct sub-page.
    • Added consent_logs SELECT policy (migration 065): users can now read their own consent history instead of the table being service-role only.
    • Removed orphaned inline SVG block from landing page that was causing 5 typecheck errors and a lint parse error.
  50. v3.6.0

    GDPR cookie consent, QA audit hardening, and pixel.js removal

    • GDPR cookie consent banner: a new CookieConsentBanner component appears on first visit, stores the user's choice in localStorage, and logs it to the consent_logs table via /api/internal/consent — essential-only and accept-all options, with a link to the Privacy Policy.
    • Info tooltips (ℹ️) added to every profile section that needs explanation: Settings page cards (Notifications, Tracking, Payouts, Data Export, Session Timeout, Security), Appearance and Connected Accounts sections, and the creator Media Kit stats grid (Total Followers, Campaigns Completed, Conversion Rate, Total Driven Sales). Public profiles already had SectionLabel tooltips on every section.
    • pixel.js route removed: the legacy /pixel.js endpoint now returns 404. The Chrome extension and desktop tracker are the only supported tracking methods; the /api/v1/pixel/ping heartbeat endpoint remains for backward compatibility.
    • Full 7-phase QA audit completed: 294 Vitest tests passing, typecheck clean, lint 0 errors, build successful. All API endpoints verified (health, tracking redirect, pixel ping, conversion webhook, domain verification, tracking status). CSP headers, rate limiting, SSRF protection, and Stripe safety all confirmed.
    • Fixed the missing CookieConsentBanner component that was imported on the landing page but never created — the GDPR consent banner now renders correctly.
    • Cleaned up pixel.js references in tracking status, pixel ping, and conversion webhook route comments.
  51. v3.5.0

    SocialVerify — independent social-account verification

    • SocialVerify campaign flow: select any combination of YouTube, TikTok, Instagram, and Twitter/X, and the campaign stays locked until every selected platform is verified.
    • Cryptographic verification tokens: each platform gets an HMAC-signed token with a 7-day expiry, a countdown, and auto-rotation — post it to your bio to prove ownership.
    • No-API authenticity scoring on a 100-point scale (engagement rate, comment quality, posting consistency, growth velocity, cross-platform, plus a challenge bonus) from public post data or signed self-reported metrics — no privileged platform API keys required.
    • Seven-proof identity binding to stop impersonation: domain ownership, bi-directional links, time-delayed token persistence, video proof, a two-way handshake, historical content, and social-graph analysis, combined into a confidence score.
    • Signed domain manifest at /.well-known/social-verification.json — a cryptographically signed, public record of your verified accounts that anyone can audit independently.
    • Full audit with weighted scoring (signature, token match, authenticity, cross-platform) and an immutable audit log.
    • A five-step business dashboard (Select Platforms → Tokens → Identity → Audit → Authenticity) with a lock banner, monospace token cards, proof-of-identity cards, and a circular score ring.
    • Creator tiers now follow a clean 10× ladder — Small 10K, Moderate 100K, Big 1M — applied consistently across onboarding, eligibility, the marketplace, and SocialVerify platform minimums.
    • Creator onboarding Step 2 is now a dedicated four-step wizard (Platform → Details → Verify → Review) with a progress bar — pick a platform, enter your handle and followers to see your tier live, copy your per-account proof code into your bio, and upload a screenshot for admin review, all before advancing. The Instagram/TikTok OAuth dead-ends were removed so manual verification is the one clear path.
    • Public SocialVerify report for businesses: every campaign is now shareable at /audit/business/:id (plus a no-auth JSON API at /api/v1/audit/business/:id) showing the company, per-platform verification, overall authenticity score, and identity confidence — mirroring the creator audit page.
    • The creator dashboard's Connect Instagram/TikTok buttons were removed — YouTube self-serve ownership proof and manual token-in-bio + screenshot verification are now the only connect paths, so no creator hits an unconfigured-OAuth dead end.
  52. v3.4.0

    Platform hardening, account deletion, and campaign assets

    • Self-service account deletion from Settings → Danger zone: creators are blocked while they have pending-hold earnings, businesses while a pre-paid balance remains, and completed deletions GDPR-anonymise reviews (identity redacted, rating + date retained) before removing the account.
    • Campaign asset upload: businesses can now attach a preview image or video to a campaign (JPEG/PNG/WebP/GIF/MP4/WebM, max 25MB) via a new campaign-assets storage bucket.
    • Cursor (keyset) pagination for the creator campaign feed — stable ordering with no skips or duplicates as new campaigns are posted, with a next_cursor for loading more.
    • Monthly partition maintenance replaced the stub cron: a dynamic SQL function now creates the next 3 months of partitions for clicks_log and daily_conversion_rollups on the 25th, safely and idempotently.
    • Monitor-only UptimeRobot verification is now available: map one monitor ID in Tracking settings and the third tick checks it with a server-side monitor-scoped key — no all-account access or automatic monitor provisioning.
    • Follower re-check worker: a monthly cron re-fetches each connected social account's live follower count, recomputes the creator's tier, and refreshes badges — gracefully skipping any platform whose API keys aren't configured yet.
    • Team seats lifecycle: business owners can invite teammates by email (with plan seat-limit enforcement), invitees accept or decline, and owners can remove members — and the owner is notified in-app the moment a teammate accepts or declines.
    • Team invitations now send a branded email with a one-click accept link, and brand-new invitees get a password-set link so they can log in with a password right away.
    • Campaign preview upload button added to the campaign editor — pick a local image or video and it's stored on the new campaign-assets bucket when the campaign is saved.
    • Google sign-in is now admin-controlled: it stays blurred as Coming soon on login and sign-up until a superadmin flips it live from the Superadmin dashboard — to be done only after the Google Cloud OAuth redirect URI is registered.
    • Admin account management: the Superadmin user directory now shows each account's plan and payments state, with actions to cancel plans, pause/resume payments, and terminate accounts (cancel plan + ban + pause payouts) — all audit logged, and payout/charge jobs skip paused accounts.
    • Notifications no longer auto-mark everything read on open — each row has its own Mark read action plus a Mark all read button.
    • Admin cancel-plan and terminate can now also cancel the underlying Stripe subscription (behind a second explicit confirmation so billing only stops when intended), and canceled plans can be resumed — restoring features and, with confirmation, reactivating a period-end-canceled Stripe subscription.
    • Paused-payment accounts now see a banner on every dashboard page (rendered by the shared shell), not just the overview.
    • TikTok Connect entry points were removed in favor of Instagram/YouTube Connect plus manual screenshot verification (admin-approved), so creators can still get verified and tiered without TikTok's domain-verification requirement.
    • YouTube follower counts can now be looked up with a plain API key instead of OAuth: the monthly follower re-check resolves a channel by handle via the YouTube Data API, so YouTube verification works without the Google consent screen.
    • Self-serve YouTube verification now proves ownership before auto-verifying: paste your channel handle and we ask you to add a one-time per-account code to your channel About, then confirm the live description contains it — no OAuth, no screenshot, no admin, and nobody can claim a channel they don't control. Available in the dashboard and during onboarding.
    • Admin follower-screenshot approval now cross-checks a YouTube claim against a live API lookup at approval time, so the verified count is the real subscriber count rather than the self-reported one.
    • The manual verification form now states explicitly that a self-typed follower count is never auto-verified — it always requires a screenshot and admin review (or a YouTube ownership code), closing the impersonation gap.
    • Twitter/X added as a fourth verification platform — token-in-bio + screenshot + admin review with no privileged API, following the existing follower-tier system.
    • Every manual screenshot verification now issues a per-account proof-of-ownership code: creators post it to their bio and show it in the screenshot, and admins see the expected code so they can confirm the account is real rather than a copy.
    • Public verification report: each approval writes an immutable, publicly-readable audit entry — a shareable page at /audit/:creatorId and a no-auth JSON API at /api/v1/audit/creator/:id showing platform, handle, snapshotted follower count, threshold met, and ownership-token match.
    • Fixed password + authenticator login failing with a Bearer-token error: the 2FA challenge now reuses the client that completed the password/OTP step instead of a fresh sessionless client.
  53. v3.3.0

    Integration hub upgrade, branded email, and two-factor authentication

    • Integration hub now shows real brand logos for every app (Stripe, Resend, Supabase, Upstash, Sightengine, Google Ads, Meta, TikTok, YouTube, Instagram, X, LinkedIn, Pinterest, Snapchat).
    • Add / Remove integrations: press the green Add button to reserve a slot (counts toward your plan limit), then the card flips to a green Added state with a red Remove button. Changes are saved to your account, not just your browser.
    • Two-factor authentication (TOTP): enable 2FA from Settings → Security & 2FA with any authenticator app (Google Authenticator, Microsoft Authenticator, Authy, 1Password). Accounts with 2FA enabled must enter a 6-digit code at login.
    • 2FA at sign-up: brand-new accounts are offered authenticator setup right after creating their account — scan the QR code (or enter the secret manually) and verify one code to enable it before onboarding. Optional and skippable; you can always turn it on later from Settings.
    • Creator profiles upgraded: @handle in the header, rating shows the review count, reviews show the business, campaign, and relative time, a public Campaign History section lists completed and active work, and the friend button gains Added / Copy Username / Message actions.
    • Verification badges now match spec: blue = paid plan + at least one verified social account; gold = Premium plan + 1M+ followers on a verified platform.
    • QR-code sign-up and sign-in fallback: if the confirmation or one-time email never arrives, scan a QR code with any authenticator app and create your account (or log in) with the 6-digit code — no email needed.
    • Business profiles upgraded to match creators: Verified/Gold badges, the verified domain in the header, a Connected channels panel, Recent Reviews showing the creator, campaign, and relative time, and a real Campaign History — plus ℹ️ hover tooltips on every profile section explaining what it does.
    • Microsoft (Azure AD) sign-in button added to login and sign-up — it lights up as soon as the admin enables the provider in Supabase Auth.
    • Landing page gained an Integrations section showing every supported platform with its real logo.
    • Single-session enforcement: only one active login per account — if another device or tab signs in, the older session is instantly kicked to a Session Ended screen with the masked email and a Contact Support button. Prevents account sharing and unauthorised access.
    • Custom SMTP configured: verification, reset, and OTP emails now send via Yahoo SMTP from adswishdevteam@yahoo.com.
    • Dark mode and custom appearance settings now reset on logout and are only applied on dashboard pages — the landing page, login, and signup always render in the default light theme.
    • Email rate limits raised for launch (confirmation/OTP/reset emails: 2 to 30 per hour per IP).
  54. v3.2.0

    A/B ad assets, Google Partner credits, and email-link fixes

    • A/B thumbnail assets: three frames auto-extracted from approved creator videos (10% / 50% / 90%), pick the winner for your ad creative.
    • Google Partner credits: apply for the £500 first-campaign credit straight from the Google Ads dashboard.
    • Blended ROAS dashboard: organic revenue (via your tracking links) and paid revenue side by side, revenue-by-source breakdown, and a 30-day organic series.
    • Email links fixed: confirmation links opened in a different browser or device now verify your email automatically instead of failing with a PKCE error.
    • Forgot-password flow: reset links land on a new set-a-new-password page.
    • Supabase auth config corrected: site URL pointed at the live domain and the redirect allowlist now covers localhost and the production domain.
  55. v3.1.0

    Google Ads amplification, verification badges, and session security

    • Google Ads integration: OAuth connect flow, campaign drafts and launches, pause/resume/inject controls, and a budget-protection auto-kill switch.
    • Blended Google Ads analytics view with spend, revenue, conversions, ROAS, and per-campaign charts.
    • Creator verification badges: blue badge for paid plans, gold badge for 1M+ followers on a verified platform.
    • Google sign-in now marks new accounts email-verified so OAuth signups skip the confirmation step; the verify-email page gained a resend button.
    • Session security: configurable inactivity timeout and back-button auto-logout with a clear “session has timed out” message.
    • Plan-based payout holds (Free 7 days, Pro 5, Premium 3) applied to conversion escrow.
    • Landing page rebuilt as v3 with How It Works, Guides, and live-campaign gating; Creator Marketplace demo section removed.
    • Terms, Privacy, and Subprocessors updated for Google Ads integration, OAuth data handling, and session policy.
  56. v3.0.0

    Integrations hub, plan alignment, and security hardening

    • New Integrations hub with per-plan connection limits (6 / 10 / 20) and five locked core integrations.
    • Plan campaign limits aligned across the dashboard, plan page, and enforcement layer (Growth 10, Enterprise 25, Creator Premium 25).
    • Public Changelog added under Legal, with a downloadable PDF of every release.
    • Fixed the notification-settings navigation bug caused by an over-aggressive leave-site prompt.
    • Signed-in header now shows your plan tier and role (Business or Creator).
    • Removed the native beforeunload dialog that interrupted internal dashboard navigation.
  57. v2.2.0

    Blueprint audit, currency alignment, and data controls

    • Closed the safest blueprint gaps: creator eligibility checks, active-plan limit enforcement, and real daily analytics rollup.
    • GDPR data export added to Settings.
    • Payout invoices made private, with creator-scoped signed PDF downloads.
    • Failed weekly payouts remain retryable instead of being incorrectly marked paid.
    • Admin SLA actions and manual-strike controls added, all audit-logged.
    • Live-facing currency displays and new database defaults aligned to GBP.
  58. v2.1.0

    Admin controls, manual verification, and deploy health

    • Admin account suspension, banning, and manual follower-screenshot verification.
    • Fixed the admin MFA redirect loop so the authenticator code screen loads.
    • Deploy health check and production regression sweep tooling.
    • Directory pages now show friendly empty states instead of blank grids.
  59. v2.0.0

    Creator marketplace, plans, balances, and analytics

    • Creator marketplace with tier badges, verified channels, and niche filters.
    • Subscription plans for businesses (Free / Growth / Enterprise) and creators (Free / Pro / Premium).
    • Business balance system with top-up and 90/10 cash-out.
    • Connections (friends), campaign invites, and real-time campaign chat.
    • Analytics dashboards, appearance themes, and Google/TikTok/Instagram social connections.

We use cookies to keep you signed in and attribute conversions.

Essential cookies are required for the platform to function.