JUCE Plugin Update Prompts: Notify Users Without Another Activation Barrier

Learn how to present a JUCE plug-in update notification without conflating it with activation, binary delivery, installation, or realtime audio processing.

You have shipped a new plug-in build. A customer opens the version they already unlocked, sees there is something new, and now has one reasonable question: where can I get it?

That is all a JUCE plugin update prompt needs to answer. It should not ask the customer to activate again, interrupt protected processing, or pretend the plug-in will download and install the release itself. Keeping those jobs separate makes releases easier to explain, easier to support, and less alarming for people working in a session.

For a JUCE product using Inlay, the documented pattern is straightforward: react to Unlocker state changes in message-thread UI code, inspect visible update information, and open the supplied URL only after the user chooses to do so. Keep isLocked() for its separate realtime protection job. (Source: Inlay JUCE module documentation, repository documentation reviewed 2026-07-16.)

An update notice is not an activation screen

Activation answers whether this installation may use protected functionality. An update notice answers whether a newer version is available. They may appear in the same product lifecycle, but they should not become the same interaction.

When they do, a routine release starts looking like revoked access. The customer has to work out whether the message means “there is a new version” or “you need to prove you own this again.” Meanwhile, the release team has made a licensing-state change part of announcing a build.

A clearer boundary gives each job one owner and one outcome:

JobQuestion it answersAppropriate outcome
Update availabilityIs a different version currently available to this user?Show an optional notice with a deliberate next step.
Binary delivery/downloadWhere can the user obtain the release?Provide a release or download destination.
InstallationHow does the new binary get onto the user's machine?Handle it in the product's own distribution and support workflow.
Authorization/activationIs protected functionality allowed in this instance?Maintain the product's licensing state and protection rules.

This is a product boundary, not a claim about any particular host, installer, or distribution service. It is useful when release work crosses roles: engineering prepares the build, operations publishes the destination, and the plug-in UI can announce it without claiming to do either job.

For the activation side of that boundary, see JUCE plug-in activation architecture. It covers browser activation, local access, and protected behaviour; an update notification can stay deliberately narrower.

What a non-blocking JUCE plugin update prompt should do

There is no universal JUCE or DAW rule for how an update prompt must look or when it must appear. Treat the following as product decisions. A good default is a short, optional message that:

  • says a newer version is available;
  • offers a deliberate action such as “View release” or “Open download page”;
  • lets the customer defer the decision, for example with “Not now”; and
  • avoids suggesting activation, installation, compatibility guarantees, or a forced update when it does none of those things.

That restraint matters in an audio plug-in. Someone may be mid-session; the product can acknowledge the release without turning the editor into a gate.

Placement and timing are product decisions

The message might live in a compact editor notice, on a settings or About surface, or somewhere else the product already uses for release information. Each choice trades visibility against interruption:

  • Compact editor notice: visible where the customer already interacts with the plug-in, while leaving the main work area available.
  • Settings or About surface: discoverable without interrupting the main editor flow.
  • A product-specific release surface: useful when the product already has a dedicated place for release information.

The right answer depends on the plug-in layout and the team's support workflow. The useful invariant is simpler: make the action clear, and do not turn update availability into a second activation requirement.

“Not now” and “skip this version” are different choices

Define dismissal language before building it. “Not now” is usually a temporary presentation choice that the product can model in its own UI. “Skip this version” is more specific: do not show the version currently visible again.

Inlay's documented update behaviour supports the latter. skipCurrentAppUpdateVersion() hides the current visible app update version. getAppUpdate() exposes update information only when it has a version and URL, the version differs from the running plug-in/app version, and the user has not skipped that version. (Source: Inlay JUCE module documentation.)

That gives a release owner a bounded promise: a customer can suppress the version being shown. It does not define a universal policy for every later release or a guaranteed ordering rule for future version strings. Write the product copy with the same precision. “Skip this version” is clearer than “Never show updates again” unless the product has separately implemented and tested that broader setting.

A conceptual user flow

For an already-unlocked plug-in with an available-version record, the flow can be this:

  1. The editor UI learns that update information is visible.
  2. It shows a compact notice naming the version and offering a user-initiated action.
  3. If the customer chooses the release action, the plug-in opens the supplied release/download URL in the default browser.
  4. If the customer skips the visible version, the UI calls the documented skip action and stops presenting that version.

This is a product flow, not production-ready code or an installation workflow. Publishing, download delivery, installation instructions, and customer support remain with the release process that owns them.

The JUCE boundary: update UI on the message thread, protection on the audio path

The technical split mirrors the product split. Update presentation is UI state; realtime protection is a separate concern. Inlay documents inlay::Unlocker as the owner of licensing state, activation, persistence, refresh, logout, and update checks. Because it inherits from juce::ChangeBroadcaster, UI/message-thread code can register a juce::ChangeListener and read available state when a change arrives. (Source: Inlay JUCE module documentation.)

For a custom JUCE plugin update notification, the editor can respond to an Unlocker change, inspect getAppUpdate(), and decide whether to show an update component. The user-triggered release action can use openWebsite(url) to open the supplied URL in the default browser.

The audio path has a different job. Inlay documents isLocked() as the public state method intended for realtime/audio-thread use; update methods and UI controls belong on the UI/message thread. Do not treat isLocked() as update state, and do not put update presentation or update-state reads in an audio callback. (Source: Inlay JUCE module documentation.)

The payoff is practical: release UI stays out of the code path that protects audio behaviour, and each part is easier to test and maintain.

  • The processor/protection path uses the realtime-safe lock check for protected behaviour.
  • The editor/message-thread UI listens for state changes and renders activation or update information as appropriate.
  • The user decides whether to open the release URL.

A conceptual custom-UI sequence

This is an implementation shape, not code to paste into a project:

  1. Create one Unlocker for the protected product instance and call startup() after construction.
  2. In the editor, register a ChangeListener against that unlocker.
  3. When the listener receives a change on the message thread, refresh the editor's presentation state.
  4. If getAppUpdate() exposes visible information, render the chosen update notice.
  5. Route an explicit “View release” action to openWebsite(url); route “Skip this version” to skipCurrentAppUpdateVersion().
  6. Continue to use isLocked() independently in protected realtime/audio behaviour.

The visual form of the notice is secondary. What matters is the ownership boundary: a state broadcast updates editor UI, while protected processing retains its realtime-safe guard.

DefaultUI or a custom update notification?

Inlay offers two documented paths. Neither is the universal winner.

inlay::DefaultUI is an optional component that listens to an Unlocker. Alongside activation-related states, it can show a native update prompt after unlock when Inlay reports a newer app version. It suits a product that wants the stock implementation and does not need product-specific treatment of the message. (Source: Inlay JUCE module documentation.)

A custom UI can listen to the Unlocker and use getAppUpdate(), skipCurrentAppUpdateVersion(), and openWebsite() directly. That gives the product control over placement, wording, and fit with the rest of the editor. It also makes the product responsible for keeping the interaction clear and testing its choices.

OptionWhat it providesWhen it may fit
DefaultUIOptional stock UI that can present the documented update prompt after unlock.The product is comfortable with the supplied UI behaviour and wants less presentation work.
Custom message-thread UIProduct-controlled rendering around Unlocker state and update methods.The editor needs a release notice that fits an established layout, voice, or product flow.

Both routes leave binary delivery and installation outside the prompt. A custom component does not make the plug-in an updater, and DefaultUI does not configure a distribution channel.

Release checklist: separate the work before release day

Do not make one update setting carry the whole release process. A small checklist keeps the handoffs clear.

Publish the binary

  • Build and publish through the distribution workflow your product uses.
  • Prepare the release or download destination the customer can open deliberately.
  • Keep installation and support instructions with the workflow that owns them.

Configure update information

  • Ensure the available version and its URL are present for the release.
  • Confirm the configured version is not the version currently running in the test plug-in.
  • Test the visible-update case in the intended editor UI.

Inlay documents the available-version visibility conditions and caches update information locally, including update.json; a skipped visible version is recorded separately as skipped-update.json. (Source: Inlay JUCE module documentation.)

Notify without blocking access

  • Check that an already-unlocked customer sees an update notice, not an activation flow.
  • Check that the release action is user initiated and opens the intended URL.
  • Check that dismissal wording matches the behaviour the product actually implements.
  • Check that update UI stays on the message thread and protected audio code continues to use only the realtime-safe lock guard.

Support the installation journey

  • Make the next customer step clear at the release destination where needed.
  • Keep operational questions—licenses, manual access, and recovery—separate from the in-editor update prompt.

For the operational side of licensing, see audio plug-in licensing operations. Teams managing products and license data can also use the Inlay Console guide; neither resource turns an update notice into a binary installer.

A focused update message is easier to ship and support

An audio plugin update notification does not need to solve activation, distribution, installation, and realtime protection at once. Its job is to make an available version actionable without becoming another barrier for an unlocked customer.

For an Inlay-backed JUCE plug-in, create one Unlocker per protected product instance, keep update handling in DefaultUI or a custom message-thread UI, and retain isLocked() for protected realtime behaviour. Then send people to a release URL only when they choose to go there. Follow the JUCE integration guide for module setup and current API details. The integration handles update information and UI choices; it does not configure binary distribution or automatic updates.

Source note

Inlay-specific implementation details in this article are based on the local Inlay JUCE module documentation: inlay_product_unlocking, reviewed in the repository on 2026-07-16. Recheck the current module documentation before publication if its APIs or behaviour change. No external factual sources are cited because the supplied external research did not retain publishable URLs or stable locators.