All changes

Spam protection for forms, deploy hooks that report back, and monday.com in the console

Forms can require a captcha and hold suspicious submissions for review. Deploy hooks and the monday.com integration, built but hidden until now, are in the console and working, and a workflow set to run every time no longer runs once per person.

Added
8
  • FormsForms can require a captcha, on the hosted page and in an embed, with no code to write. Pick a provider once under Forms > Spam protection, then switch on Require a captcha in a form's Protect dialog. The default, Managed by BuildBase, needs no keys or account, and your own Cloudflare Turnstile, hCaptcha or reCAPTCHA v2 Checkbox keys work too, with the secret encrypted at rest and never sent back to the console. Where the server has no Turnstile keys of its own, as a self-hosted install ships, Managed falls back to a proof of work the visitor's browser solves in about a second, with no third-party script or cookie: it makes every bot submission cost CPU time, but on its own it does not tell a person from a headless browser.
  • FormsEvery form now drops the obvious bot traffic with nothing to switch on. Hosted and embedded forms carry a hidden field a person never fills, and a submission that fills it sees the usual success message and is never stored. The same content from the same address to the same form within ten minutes is stored once, so a retrying client no longer fires form.submitted twice. For spam that gets past a captcha, the Protect dialog adds a limit on links, up to 200 blocked words or phrases, a block on 70 known throwaway email domains or on your own list, and a daily cap. A link or word hit waits for review, badged with its reason such as "3 links (limit 1)", and reaches no webhook or workflow until someone approves it.
  • FormsForms can be embedded in any website. A form's page has a Share and embed card with its link and an iframe snippet, and the embedded form resizes its frame as it grows and keeps its captcha and rules; until now the hosted form refused to load in a frame at all. A form you render yourself can carry the captcha too: the public form read names the widget and its site key, and the token travels in a _captcha field that is removed before the submission is stored or sent on. Require a captcha is off by default, because a form your own code posts sends no token until you add one, and on your own domain it needs the built-in check or your own keys, since the managed Turnstile key only works on BuildBase's own hostname.
  • Deploy hooksDeploy hooks are in the console, under Settings > Configuration. Save a deploy hook URL from Vercel, Netlify, Cloudflare Pages or Render, and the banner at the top of the console lists the blog posts changed since the last deploy and starts a build on the hook you pick. The screens were built but had no menu entry, and no step worked: a hook's first deploy was refused, and hooks were called with a GET, which Netlify and Cloudflare Pages do not build on. Adding a hook now refuses a URL that cannot start a build, such as a site address or a provider's dashboard page, and the deployment history never returns a hook's URL, since anyone holding it can start a build. Three new docs pages, with screenshots, cover each provider.
  • Deploy hooksA deploy from a Vercel hook reads Success, Failed or Canceled for the build it started. Point a Vercel webhook at BuildBase (Vercel offers them on Pro and Enterprise teams) and save its secret on the hook: only events signed with it count, and when Vercel cancels an older build because a newer one replaced it, the old deploy reads Canceled and the new one Success. If a build fails or is canceled before its content went live, the banner offers that content again instead of marking the hook up to date. A Deploy status column on the hooks list says whether the webhook works, from Not set up to Connected or Secret does not match.
  • IntegrationsThe monday.com integration is in the console, under Apps. If your product ships a monday.com app, BuildBase runs its OAuth sign-in, records every install and uninstall, and forwards those events to your server, and the Settings tab opens with a five-step setup guide in the order monday's Developer Center asks for things. The screens were built but had no menu entry, and the main path was broken: a first install was refused before it reached monday.com's consent screen, every lifecycle event failed until a forward URL was saved, and the URLs the console told you to paste into monday.com pointed at the wrong host. All of it works now, credentials can be edited after Connect, there is a Disconnect, and three docs pages cover the setup.
  • IntegrationsYour monday.com app server gets two more URLs. Tokens from monday's new OAuth flow expire after a day, so the token handed over at install is dead by the next one; the Token URL answers a request signed with your client secret with a token refreshed as needed, and says when the person has to sign in again. And because monday workflows do not support the Authorization URL older integrations used, BuildBase now answers the Credentials URL and Delete Credentials URL that monday's replacement needs: one lists the person's saved sign-in without its token, the other removes it and revokes its tokens at monday.com too.
  • AgentsAllow agent self-signup is on the Agent readiness screen under Authentication. With it on, your server can create an account for an agent with no person behind it, in one call to POST /api/v1/auth/agent/register made as one of your OAuth clients; the account has no console access and counts against your plan's end-user limit. The endpoint was built and documented, but its switch was missing from the console, and it now accepts only OAuth clients an admin created, never a public or self-registered one. Turning dynamic client registration on or off also reaches the metadata agents read at once, where it could lag by five minutes.
Improved
8
  • BillingAn upgrade waiting on its payment, for a card that needs 3-D Secure or was declined, is no longer announced before it is paid. subscription.upgraded, the Slack notice and the workspace notification go out once Stripe applies the upgrade, and an upgrade that is never paid is dropped without one. In the next SDK release, Plan & Billing shows Complete payment with Stripe's invoice page instead of saying the plan was updated.
  • BillingBuildBase listens for two more Stripe events, customer.subscription.pending_update_applied and customer.subscription.pending_update_expired, so a paid upgrade applies as soon as Stripe confirms it and an unpaid one clears at once. An existing webhook endpoint needs them added: the Stripe setup check on the payment credentials page lists them as missing, and Fix the endpoint for me adds them. Until then upgrades still apply on invoice.paid.
  • ConsoleMore of the console says when something failed. A list whose request failed shows the error and Try again instead of an empty list or a zero, and a user page says Not found only when the user does not exist. The notification settings drew push and email as on when they could not be read, and a user's Devices tab said "No devices recorded"; both show the failure now. Delete, archive and confirm dialogs wait for the server and report a refusal instead of closing first, a refused invitation no longer says "Accepted", and Grant credits, Revoke credits and Reconcile on a workspace, which drew as buttons and opened nothing, work.
  • ConsoleThe console shows more of your plan's limits, where each one applies. Fifteen more limits have a usage meter, among them assets, audience and user lists, smart lists, deploy hooks, tracking scripts and workflow templates, and every meter recounts after a change. Eight features a plan can leave out show a lock on the control they govern, such as your own SMTP sender, targeting a feature flag at specific users, retrying from the dead-letter queue and audience bulk import. Assets can also be deleted now: there was no way to remove one, so every upload counted toward the asset limit for good.
  • PlatformOne organization can make at most 1,200 writes a minute through the console and organization APIs, however many API keys and sessions it spreads them across. The existing limits were per address and per API key, so an organization writing on several keys had no ceiling of its own, and its burst could queue ahead of other customers' work. A write over the limit is refused with "This organization is making changes too quickly". Only POST, PUT, PATCH and DELETE count, the SDK routes your end users call are not covered, and the number is the same on every plan.
  • Deploy hooksDeploys on the other providers say more. A Netlify build BuildBase starts reads "Deploy triggered by BuildBase hook" and the hook's title in Netlify's deploy list, instead of Netlify's generic hook message. A Render deploy that Render queued behind one already running reads Queued rather than Triggered, and a Render deploy links to it in your Render dashboard. View response on any deploy says which HTTP status the hook answered.
  • SDKPlan comparison tables and plan cards print "Unlimited" where a plan has no ceiling and a dash where it leaves something out, instead of -1 and 0. On our own live plans that was seven cells reading -1 and seventeen reading 0. That is @buildbase/sdk 0.0.82; from 0.0.81, a freemium plan reads "Start free" rather than "Subscribe" when there is no subscription yet, since there is nothing to pay. Both are in all eight locales.
  • PlatformLookups by a unique key on records that can be deleted now have an index they can use, on 48 collections in every organization's database. Those lookups scanned the collection instead: rollup lookups alone examined about 1.3 million documents in one test run's query log. That corrects last week's entry, which credited the rollup fix to the query itself; this index is what makes those reads cheap. A server builds the new indexes once, in the background, on its first start after updating.
Fixed
16
  • BillingChanging plan during a free trial no longer ends the trial. The trial keeps running on the new plan and ends when it would have, and the new plan is billed then. Until now a plan change ended the trial at once: a trial started without a card had nothing to charge, so Stripe cancelled the subscription and the workspace landed on the paywall a moment after a Plan Upgraded notice, and with a card on file the new plan was charged at the click. The trial-ending banner now asks for what keeps access, a payment method, with Add payment method opening the billing portal, instead of Choose a plan.
  • WorkflowsA workflow set to "Allow always", the default, now runs every time it is triggered, and one set to "Cooldown" runs again once the cooldown has passed. Both ran once per person: the guard against duplicate triggers was meant to last 60 seconds but was also a unique key on a run record kept for a year, so a second login or the next monthly renewal for the same person was skipped as a duplicate. Only a repeat inside the same 60 seconds is refused now. A workflow that relied on running once should be set to "Once only".
  • PlatformA request that names a record by an id that is not a valid id now answers not found. The lookup lost its only condition on the way to the database and matched the organization's first or newest row instead, so a malformed campaign id acted on the organization's first campaign, and cancelling a pending ownership transfer sent the withdrawal notice to an unrelated account rather than the person it was offered to. A key, slug or email of exactly 12 characters, such as [email protected], went the other way: it was read as a database id and never found. Attributes, audience members, rich-content blocks, plans and plan items now find it.
  • SecuritySecrets nested inside a setting were stored unencrypted when it was created, and encrypted only if that field was edited later: the client secrets of social sign-in providers, an email sending account's SMTP and Google credentials, server-side tracking secrets and the Google Ads refresh token. They are encrypted on create now; one saved before the fix and not edited since stays unencrypted until it is saved again, so re-enter it to encrypt it. The request log also stops writing credentials carried in a URL, such as a magic-link or password-reset token or an OAuth code: the value reads [redacted].
  • SecurityThe push subscribe endpoint accepted any address as a push endpoint. In production it now accepts only the browser push services (FCM, Mozilla, WNS and Apple) and checks the rest of the subscription, and a stored subscription that fails those checks is never called. The subscriber list returned each subscription's encryption keys to any member who could read campaigns; the keys never leave the server now, and a subscriber's IP and location go only to members who may read users. Two organizations sending at the same moment could also have their pushes signed with each other's keys; each send carries its own.
  • EmailBlocking a user now stops the email linked to them. The check matched the organization's newest user instead of the recipient, so whether a linked email went out depended on one unrelated account. Retrying an email whose queue job had expired said "Email being retried" and queued nothing; it resends now. Bounces, complaints and unsubscribes reported by the mail provider now reach the contact's activity timeline, and the email.bounced and email.unsubscribed events your webhooks and workflows receive carry the contact's audienceId instead of "[object Object]".
  • BillingA plan now sets the workspace features it manages. A feature marked "Subscription managed" was never written onto the workspace when a plan was assigned, changed, restored after a failed payment or reset for the month; a workspace picks up its plan's values the next time one of those happens. Reading the subscription of a workspace whose plan sat in no published pricing group failed, which the console showed as "no active subscription"; it answers with the subscription now.
  • FormsA published form no longer gives away who built it. Its public read, which answers anyone with the form's link, included the name, email address and profile image of the staff member who created the form; it answers without them now. The hosted page never used them, and your team still sees the creator in the console.
  • NotificationsA push campaign sent to a list where nobody could receive push went to every push subscriber in the organization, because an empty list read as no list. It is refused now, before the campaign is marked sent, and so is a campaign sent with push switched off for the organization, which went out anyway, or with no VAPID keys, which showed Sent while reaching no one; each refusal says why, and the campaign stays a draft. Delivery logs also finish, as sent, partial or failed with a short reason, instead of staying at processing.
  • IntegrationsA monday.com app with New OAuth flow switched on can be installed. Every install was refused with "code_challenge is required"; the sign-in now sends the PKCE challenge and redirect URL the new flow asks for, so the Redirect URL registered in your monday.com app has to match the one the console lists. Tokens from the old flow, which monday.com is retiring, are traded for OAuth 2.1 tokens automatically with no one asked to consent again (all six in our test organization moved), and installer tokens, stored as plaintext until now, are encrypted at rest.
  • IntegrationsSigning in through your monday.com app created a verified user even with public sign-up switched off, and ignored the end-user limit; it obeys both now, like every other way a user is created. Process events, which adds everyone who installed your app to your audience, could pass the plan's contact limit; it stops at the same allowance a CSV import uses and says how many people it left out. With no Auth callback URL set, an installer was also sent back to monday.com with the access token still in the URL, where it stayed in browser history; nothing is added to that URL now.
  • PlatformOrganizations created before 12 June can reuse a value that belonged to something they deleted. Their databases kept unique indexes from before deleted records were exempted, so a rich-content or collection slug or an attribute key answered 409, a removed auth domain could not be added back, renaming a post to a deleted post's slug failed, and a browser that subscribed to push again after unsubscribing got an error and no working subscription. Those indexes were replaced on BuildBase cloud on 15 October, without leaving any value unguarded during the swap.
  • Self-hostingCalls from BuildBase's central server to a self-hosted installation, such as revoking a removed member's access, now carry the API key the installation checks. The central server stores that key encrypted and sent it as stored, so the installation refused the call; only a key regenerated under Account > Installations worked, because regenerating saved it without encryption. Every installation key is now stored encrypted and decrypted only to be sent, and a key the central server cannot decrypt stops the call.
  • Short linksAn archived or deleted short link answers 404 from its own organization at once. An archived link's next click, or any click on a deleted one, searched every organization on the server; on a test stack of about 1,250 organizations each such 404 took 138 to 216 seconds. Unarchiving a link works on the next click instead of staying 404 behind a cached miss, an archived link can no longer resolve to another organization's link with the same id, and a live link's click reads one index entry instead of scanning the organization's links.
  • SDKPush notifications shown by the SDK's service worker keep what the server sends: the image, action buttons, staying on screen when asked, and replacing an earlier notification with the same tag, where the worker showed only a title, body and icon. The tracked click link also wins over a url in the payload's data, so that url can no longer skip click tracking. That is @buildbase/sdk 0.0.83: an app that writes public/push-sw.js from PUSH_SERVICE_WORKER_SCRIPT at build time gets it on upgrade, but a hand-copied worker, including the one the README used to show, has to be replaced with that build step. The push docs also stop telling you to wrap your app in PushNotificationProvider, which SaaSOSProvider already mounts.
  • ConsoleConsole tables and pages fit the screen. Columns without a set width were fixed at 150px, cutting titles and URLs while a wide screen showed an empty band; columns now share the spare width, 28 of the 124 columns holding buttons were widened after measuring each one, and text that still does not fit ends in an ellipsis with the full text on hover. On a phone, Authentication's eight tabs drew a 991px strip on a 390px screen and several page headers ran past the edge; tab strips and headers now scroll inside their own row. The IP column on Beta users, always empty before, shows the IP.

Use what shipped this week

Everything in this release is already in the console and the SDK.

7-day free trialNo credit card requiredCancel anytime