Designing a Keyless 30-Day Trial System for Joomla Extensions
A practical look at fair trials and central entitlement for Joomla developers
Written by: Jason Crimmel - Founder, QuantaCade · Software Product Architect & Joomla Extension Developer

 

A trial sounds simple until you try to make it fair.

Suppose an agency installs an extension on a Friday afternoon, but the client will not review it until Monday. Should three days of a 30-day trial already be gone? What if the package is installed on staging first, or deployed as part of a larger site build weeks before anyone opens the component? What if a crawler touches a frontend route, or a scheduled job runs before an administrator has even looked at the product?

Those questions are not really about licensing. They are about what counts as a genuine evaluation.

When we began redesigning the trial system used by QuantaCade's paid and tiered Joomla extensions, the product goal was deliberately simple: install the normal package, require no trial key and no credit card, and let an administrator evaluate the highest feature tier for 30 days. Installation alone should not start the clock. Frontend visitors should not start it. Background jobs should not start it. A real administrator action should.

That friendly part was easy to describe. The harder part was deciding where the truth about the trial should live.

A Joomla extension runs on infrastructure controlled by the customer. The site owner can read PHP, change PHP, edit database rows, alter Scheduled Tasks, restore a backup, clone the site, delete local component state, change an installation identifier, block outbound requests, or simply reinstall the package. That is not a flaw in Joomla. It is part of the reason people use an open, self-hosted CMS in the first place.

So a useful trial system cannot begin with the assumption that a local timestamp is untouchable. It cannot make an installation UUID the sole identity of a trial and then be surprised when a new UUID appears. It cannot treat "the license server did not answer" as permission to keep the last known premium state forever. At the same time, it should not punish legitimate customers because a network route failed for an hour.

The problem becomes much more interesting when stated this way: which facts belong on the Joomla site, and which facts must be authoritative somewhere the local installation cannot reset?

Joomla licensing is already a spectrum

There is no single commercial licensing model in the Joomla world, and that is worth saying before describing a more active entitlement system. Different developers have made reasonable choices for different products.

A traditional model is to sell access to a Pro package, updates and support while allowing the installed software to keep running after the subscription expires. Regular Labs, for example, publicly says that a customer who does not renew can continue using the version already downloaded without restrictions, while updates and premium support end. Its current Extension Manager uses a Download Key to obtain entitled Pro packages and explicitly says an installed Pro package is not silently downgraded when an update is unavailable.

JoomUnited takes a similarly straightforward position on its current Joomla bundle: the version you have is not date-limited, while the membership provides updates and support. StackIdeas publishes another variation. Its PHP code is GPL, it allows use on more than one domain, and its registered domains are primarily tied to services such as downloads, support, automated updates, its app store and language services.

Akeeba's Download ID model illustrates a useful middle ground. The Download ID identifies the account when Joomla requests a Professional update, and the server checks whether the account has a qualifying active subscription. Akeeba also documents that some remote-storage integrations using its OAuth mediation require an active entitlement. In other words, the local extension and the vendor-hosted service do not have to follow exactly the same authorization rule.

JoomShaper offers yet another mix. SP Page Builder Pro is a distinct package, and its license key is used for official updates. Its public documentation says pages that were already built continue to operate after membership expiration, even though updates, support and some account-connected Pro resources are no longer available.

None of those approaches is a target for criticism here. They show why the phrase "industry standard licensing" can be misleading. There is a continuum from "buy the package and keep using it" to "your current subscription determines your active feature tier." QuantaCade sits closer to the second end because its products use Basic, Pro and Max tiers, a premium preview can temporarily elevate a site to Max, and some products also use services running on QuantaCade-controlled infrastructure.

That distinction matters. A developer selling a small local plugin for a modest one-time fee may gain almost nothing from building an entitlement platform. A developer operating a product family with subscription tiers, hosted services and real ongoing infrastructure costs has a different problem.

There is also an important Joomla-specific boundary around all of this. GPL rights and commercial entitlement are related, but they are not the same thing. The GPL answers what a recipient may do with the distributed code. Entitlement answers what the vendor currently recognizes for updates, support, hosted services, account benefits or a product tier. A commercial Joomla developer should not pretend an entitlement system overrides the GPL, and should not build a business model around making customer-owned PHP impossible to inspect.

The Joomla Extensions Directory adds its own policy layer beyond the GPL itself. Its current submission checklists disallow per-domain use restrictions in a listed extension and put conditions on call-home behavior; the directory also has separate rules for extensions that bridge to cloud or SaaS services. That does not reduce every commercial model to the same design, but it does mean a developer considering active runtime entitlement should read the current JED rules carefully instead of assuming that "GPL-compatible" automatically means "JED-compatible." How a Basic package, paid tier, hosted service and directory listing are separated can matter as much as the code.

Put the clock somewhere reinstall cannot erase it

The central architectural choice we made was to stop treating the local Joomla installation as the owner of the trial clock.

The site still does a lot of work. It knows which product it is. It creates an installation UUID. It stores a local entitlement cache and, after the trial has been established, an opaque preview token. It runs a Joomla Scheduled Task that refreshes entitlement. It decides which local features to show based on the effective tier it has most recently confirmed.

But the durable facts live centrally: whether that product on that normalized domain has already used its preview, when the preview started, when it ends, what current product policy applies, and whether a vendor-hosted premium operation should be allowed.

The anti-reset identity is intentionally not the installation UUID. It is the combination of product and normalized, verified domain. That sounds like a small choice, but it changes the character of the system. Uninstalling the component does not erase the central record. Deleting local tables does not erase it. Generating a new installation UUID does not make the domain new again. Restoring an old copy of the site does not move the central clock backward.

On the server, the preview history sits in a shared ledger with a database-level unique key for the product and domain pair. Database uniqueness is important because it closes a race condition that application code alone can miss. Two first-use requests arriving at nearly the same moment should not be able to create two independent preview histories.

The preview duration is also server-side policy, not a trustworthy constant supplied by the extension. In our current implementation the policy says 30 days, but the architecture is not inherently a 30-day architecture. The same protocol could support 14 days, 45 days, no preview at all, or a different verification route for a future product without teaching every installed copy a new business rule.

That separation between policy and protocol paid off during the rollout. We converted eight paid or tiered products to one generic central licensing and preview engine. Most of those products did not need their own license API on the QuantaCade server. A product-specific central endpoint is only necessary when the product has a separate premium operation that actually happens on QuantaCade infrastructure.

For an agency or vendor with a family of extensions, this is one of the most important lessons in the project. A licensing architecture becomes much easier to live with when "new product" does not automatically mean "new license server."

A simple authority split

Customer Joomla site

Vendor / central service

Executes the extension

Creates installation identity

Stores raw preview token and local cache

Runs Scheduled Task

Applies local feature gates

Stores product policy

Owns durable product/domain history

Creates fixed start and end dates

Stores preview-token hash

Authorizes vendor-hosted premium operations

 

The local site is therefore a participant in entitlement, not the owner of durable trial history. That is a more realistic role for software running in a customer-controlled environment.

Proving that the Joomla site is really there

A central ledger solves the reinstall problem, but it creates another question: what stops someone from claiming a domain they do not control and asking the server to start a trial for it?

The first-use flow answers that with a short-lived challenge.

When an authorized administrator first opens the extension, the local code checks whether the entitlement machinery is healthy. If it is, the extension generates a random challenge, stores it briefly, and sends a preview request to the central service. The request includes the product, site URL, normalized domain, installation UUID and challenge. It may also include version information that is useful for diagnostics.

The central service does not immediately start the trial. First it looks for existing history for that product and domain. If a preview is already active, it returns the same fixed dates. If the domain already consumed the preview, reinstalling does not create a new one. Only a domain with no prior consumed preview reaches the proof-of-control step.

At that point the vendor server calls the Joomla site back over HTTPS using a small verification route that belongs to the extension. The route returns a tiny JSON response containing the same random challenge, the installation UUID and the product code. If they all match, the vendor has evidence that the live Joomla installation that requested the preview can answer the challenge.

Only then does the central service create the fixed preview window and issue an opaque token for later revalidation. The server stores a hash of that token rather than needing the raw bearer value in its database. The Joomla site keeps the raw token.

This callback is simple enough to explain, but it is also one of the places where a casual licensing project can turn into a security project. If your server is willing to make an HTTP request to an address chosen by a customer, you have created a potential server-side request forgery path. The verifier should not become a generic URL fetcher.

Our implementation therefore requires HTTPS, requires the URL host to match the normalized domain being claimed, rejects embedded URL credentials, resolves the host and refuses private or reserved addresses, verifies TLS, does not follow redirects, and pins the request to an IP that was just checked as public. That last point matters because merely checking DNS and then making a fresh request leaves room for the DNS answer to change between the safety check and the connection. The response itself must be a successful HTTP response containing strict JSON with the expected challenge, product and installation identity.

You do not need an engineering degree to use this pattern, but you do need to respect what your code is doing. The moment a licensing server calls customer-provided network locations, the licensing server is a network-security endpoint.

One of our more useful production lessons had nothing to do with cryptography. The verification endpoint was returning the right JSON, but one product merely returned from its component entry file after echoing the response. Joomla was still free to continue rendering the site template around it. From a browser it looked close enough. From the central service, which correctly expected pure JSON, it was invalid.

The fix was to terminate Joomla processing immediately after writing the verification response. It is a small detail, but it captures a larger rule: test the HTTP response that the other machine actually receives, not the PHP branch you believe should have returned.

The scheduled task is part of the entitlement model

Once the preview exists, repeatedly calling the customer site back would be unnecessary and intrusive. Normal revalidation uses the opaque token through the central license API. On the Joomla side, a Scheduled Task performs that refresh on an hourly cadence.

The important detail is that the task is not just background convenience. Its health is part of the entitlement decision.

That distinction came up in a very practical question: what if a user leaves the task enabled but changes it to run once every ten years? A naive system that checks only the task's published state could accidentally make the last known Max result almost permanent.

We do not treat "enabled" as equivalent to "healthy." The extension checks that the task plugin exists and is enabled, that Joomla's scheduler is available, that exactly one canonical entitlement task is published, and that its cadence is no slower than hourly. It can also report when the task is badly overdue or its last execution failed. A ten-year schedule is therefore unhealthy even though Joomla would still call the task enabled.

There is a second protection because schedule metadata alone is not enough. A determined administrator could make the task look hourly while preventing it from actually talking to the server. The local entitlement cache carries the time of the last successful central confirmation, and that confirmation is allowed to become stale only for a bounded period.

The current continuity window is 24 hours, and the wording matters. It is not a bonus day added to every subscription or preview. It exists only for a genuine communication failure after an above-Basic entitlement was successfully confirmed. A DNS problem, temporary route failure or central outage can qualify. An explicit response saying the preview expired, the license was revoked or the domain was denied does not.

Known expiration is also a hard ceiling. If the site already knows that its preview ends at noon tomorrow, blocking the network at 11:59 today does not create another 24 hours after noon. The cache can bridge a temporary inability to communicate only inside the entitlement period the site already knows about.

This failure taxonomy is more important than it sounds. Licensing systems often become unpleasant in one of two directions. They either fail closed on every network hiccup and punish paying customers, or they fail open indefinitely and turn "disconnect the license server" into a bypass. Treating transport failure differently from an authoritative denial lets you avoid both extremes.

It also keeps ordinary page requests fast. A central authority does not imply that every frontend hit needs a synchronous license check. The useful pattern is central authority, local cache, and explicitly bounded staleness. The site can render from recently confirmed state, while the scheduler handles routine renewal of that state in the background.

We describe the local cache as tamper-aware, not tamper-proof. A signature or keyed hash (HMAC) can detect casual database editing, but any secret embedded in PHP on a server owned by the customer is ultimately available to a determined administrator. That is a limitation to design around, not a marketing problem to hide.

The hardest boundary is the one you actually control

This is where the difference between local premium features and vendor-hosted premium services becomes important.

If a Max feature runs entirely in PHP on the customer's server, a sufficiently determined developer can patch the local gate. They can make a function that normally asks "is this feature allowed?" return true. They can remove a task-health check. They can hardcode the effective tier. If your source is distributed and readable, you should assume that possibility exists.

There are ways to make that kind of tampering more annoying, but we deliberately did not make obfuscation, encoded PHP, invasive anti-debugging or constant file-integrity checks the foundation of the system. Those approaches create compatibility and support problems, sit awkwardly with Joomla's open-source culture, and still do not give the vendor a truly hard boundary on a machine the customer controls.

A much stronger boundary exists when the premium operation itself happens on infrastructure you control.

Two QuantaCade products made this distinction concrete. QC Digital Signature has central authorization around some request and identity-verification operations. QC Memberships & Meetings has central services for meeting-room and resource-reservation functions. In those cases the local extension does not get to decide by itself that a premium operation should happen. The server performing the work checks current entitlement again.

This does not mean every premium feature should be moved into the cloud to make licensing stronger. That would be the wrong lesson. Joomla's self-hosted nature is a feature. Moving ordinary local features to a remote service only to make them harder to patch can turn a useful extension into an unnecessary SaaS dependency.

The better principle is narrower: if a feature already consumes vendor-controlled compute, storage, API quota, meeting capacity or other hosted resources, authorize it where those resources live. If the feature is genuinely local, accept that local enforcement has an upper limit.

That design also prevents a subtle architectural mistake: a secondary premium service should not become another way to start a virgin trial. In our system, only the generic verified preview path can create the first 30-day window. A hosted service can recognize an already-established preview and decide whether to perform its premium operation, but it cannot independently mint a fresh trial. One action should have one authority.

What it takes to run this in the real world

The infrastructure is less exotic than the architecture may suggest.

On the customer side, a normal Joomla-capable host is usually enough. The site needs HTTPS, working Joomla Scheduled Tasks, outbound HTTPS so it can reach the entitlement service, and a publicly reachable HTTPS verification route for the first-use callback. Standard PHP cryptographic and random-number functions are sufficient. There is no required desktop license manager, no daemon that has to run beside Joomla, and no WebSocket connection held open to the vendor.

That means ordinary shared hosting can support the design. Apache, Nginx or LiteSpeed are not the deciding factors. The bigger questions are whether HTTPS works correctly, whether outbound requests are allowed, whether the scheduler actually runs, and whether a firewall or WAF will permit the short verification callback.

Private environments are a different story. A localhost install, VPN-only intranet or staging site hidden behind HTTP authentication is not publicly verifiable using this callback model. Agencies run into these cases more often than individual site owners. If agencies are part of your audience, you need a deliberate development and staging policy rather than pretending every Joomla installation has a permanent public production domain.

The vendor side is also conventional web infrastructure: an HTTPS API, a durable relational database, a secure random source, hashing, an HTTP client such as cURL, DNS resolution, TLS verification, rate limiting, logging, monitoring and backups. The hard requirement is not special hardware. It is operational discipline.

And that is one of the strongest arguments against building a system like this unless the product needs it.

The moment a customer's paid features depend on your entitlement server, your server becomes part of their production dependency graph. An outage is no longer only a problem for your storefront. A database mistake can affect feature state. A bad deployment can create support incidents across several products. You need rollback procedures, monitoring and enough confidence in your infrastructure that you are comfortable making this promise to customers.

You also create new categories of support tickets. "My license key is wrong" becomes "my scheduler is duplicated," "my host blocks outbound TLS," "my WAF is rejecting the callback," "my staging domain changed," "my site moved," or "my server can reach you but you cannot reach my verification route." A sophisticated entitlement system can prevent casual abuse and still be a bad business decision if it costs more to support than it protects.

This is why false denials deserve at least as much attention as bypasses. A paying customer who is incorrectly reduced to Basic during an important operation will not be impressed by the elegance of the architecture. From their perspective, they paid and the software stopped recognizing them. A licensing false positive is a product defect, not a security victory.

The design should therefore make its own health visible. Show the administrator whether revalidation is healthy, when it last succeeded and when it will run again. Provide a manual refresh action. Preserve premium configuration when entitlement falls back to Basic instead of deleting settings the customer may need after renewal. A non-destructive downgrade gives support a chance to repair a problem without turning licensing into data loss.

There is also a privacy obligation. Entitlement traffic should carry only information that is genuinely needed. A product code, normalized domain, installation identity and token may be necessary. Joomla, PHP and extension version information can be useful for diagnostics, but if you send it, disclose it and be able to explain why you keep it. Licensing infrastructure should not quietly become an analytics system just because it already has a network connection.

Production has a way of finding the assumptions

The first-use JSON issue was not the only lesson that appeared after the architecture left a diagram and met production.

We also hit a database migration problem that is easy to miss when configuration is stored as JSON. An early SQL update attempted to write nested preview-policy paths into a parent JSON object that did not yet exist. The database could report that the row was affected while the policy values we expected were still absent. The correction was to write the entire parent preview object deliberately and then read the stored value back after deployment.

That sounds like a MySQL footnote, but the lesson is broader: a successful migration statement is not proof that the application is in the state you intended. Verify the state the code will actually read.

A related migration issue came from an older three-day preview policy. We wanted every genuinely unused preview under the new system to start at 30 days, but we did not want to resurrect or reset previews that had already been consumed. The final design used both a one-time migration for known pending records and a runtime safeguard so an eligible unused preview could not accidentally start with an obsolete three-day value. Existing active, used or expired history stayed history.

We also learned that shared architecture requires cross-product audits. Once eight extensions depend on the same entitlement rules, "almost the same implementation" is not enough. A verifier that forgets to terminate Joomla, a task that uses a different cadence rule, or a hosted service that accepts stale entitlement can create a hole that does not exist in the other seven products.

The upside is that the same centralization that raises the stakes also reduces duplication. Once a product is converted, a normal UI fix or feature release does not need a new central license endpoint, another trial table or another SQL migration. The entitlement protocol should stay boring while the product evolves. Central code changes are reserved for changes to the central contract, central policy, stored data or a genuinely new hosted premium service.

What the customer gains, and what the customer gives up

The obvious customer benefit is that the trial becomes easier. There is no temporary key to request, no card to enter and no separate crippled package to understand. The customer evaluates the actual premium tier on the site where it may eventually be used.

Starting the clock on intentional administrator use is also fairer than starting it on installation. It respects the way agencies stage work and the way site owners install software ahead of a maintenance window. Frontend traffic cannot accidentally consume the trial, and a background task cannot silently burn it while nobody is looking.

A bounded continuity window is another customer-friendly choice. A vendor outage should not instantly break a recently confirmed paid installation. Preserving configuration after expiration matters for the same reason. If a customer spent two weeks configuring a premium workflow, falling back to Basic should not erase that work. The restriction should be on use of the gated feature, not ownership of the customer's own configuration and data.

But the customer gives something up in exchange for those properties: independence from the vendor.

With a perpetual local Pro package, the vendor can disappear and the installed version may continue to work for years. With active runtime entitlement, the long-term behavior of premium features depends on the vendor continuing to operate its service. Even with a 24-hour continuity window, that is a real dependency, not a theoretical one.

That dependency deserves a business-continuity answer. If a vendor using active entitlement ever shuts down, what happens to paying customers? Does a final build remove runtime checks? Does the server remain available for a transition period? Does the product fall back to a perpetual tier? There is no universal answer, but "we will decide if it happens" is weaker than having a policy before customers depend on the service.

Phone-home behavior also needs plain-language disclosure. Some Joomla administrators operate under corporate security policies that treat outbound connections carefully. Others simply dislike software that talks to a vendor without explanation. The right response is not to hide the connection. It is to document what is sent, how often, what is stored, what happens when the connection fails and which features actually depend on it.

This is where licensing stops being a technical mechanism and becomes part of the trust relationship between a developer and the people running the software.

What this could mean for the Joomla ecosystem

I think there is a useful community discussion here, but it is not "Joomla developers should all build entitlement servers."

If keyless evaluation becomes easier, commercial Joomla products may be easier for agencies and site owners to test before they buy. If a more sustainable paid model gives developers more reason to maintain compatibility, answer support tickets and keep products secure, the ecosystem benefits. Publishing the ugly parts of the implementation can also improve the quality of future licensing systems. A developer who reads about the SSRF problem before writing a callback service may avoid creating one.

There is an opposite possibility, too. Imagine a Joomla site with thirty commercial extensions, each running its own hourly entitlement task, each calling a different vendor, each storing tokens, and each able to reduce functionality if a remote service disappears. That would not feel like the self-hosted Joomla many people chose.

The design principle I would carry forward is therefore not "phone home more." It is "centralize only the facts that actually require central authority."

A trial's durable one-time history is a reasonable candidate because local deletion should not reset it. Authorization for a vendor-hosted resource is an obvious candidate because the resource is already on the vendor's server. A local color picker probably is not.

The same restraint applies to anti-tamper measures. Readable PHP is part of the environment. A developer can spend a great deal of effort trying to make local code hostile to its owner and still not create a true security boundary. That effort may be better spent on good updates, support, hosted services people value, and a licensing system that fails gracefully.

A Basic fallback helps here. If entitlement fails or expires, the extension does not have to become a dead brick. It can preserve data, preserve configuration and continue providing the free tier. That is a commercial decision, but it is also a community-friendly failure mode.

Agencies deserve special consideration. They are often the people who discover and recommend extensions, but their workflow involves staging domains, temporary URLs, client handoffs and site cloning. A domain-centered system that ignores those realities can frustrate the very audience most likely to bring the product into professional projects. If you adopt domain identity, design agency and staging rules at the same time, not as a patch after launch.

Should you build something like this?

Maybe. That is the answer I hope another developer reaches after reading this, rather than an automatic yes.

If your product has a free tier, meaningful paid tiers, a real need for time-limited evaluation, several extensions that can share one entitlement engine, and especially vendor-hosted premium operations with ongoing costs, a server-authoritative entitlement model can make a lot of sense. It can give customers a much better trial while making reinstall-and-reset tricks ineffective. It can also give your product family one consistent definition of what Basic, Pro or Max means today.

If you sell a small local extension, have no hosted service, expect the installed version to be perpetual, support many disconnected networks, or cannot confidently operate a central API for years, a Download Key and paid update/support model may be the better design. There is nothing unsophisticated about choosing less infrastructure when less infrastructure solves the problem.

I would also ask a harder business question before writing a line of entitlement code: is the revenue being protected large enough to justify the dependency being created? Licensing work can become a seductive engineering project. It has tables, tokens, edge cases, security rules and satisfying failure states. None of that guarantees it is the best use of a developer's time.

For us, the most valuable parts of the QuantaCade design ended up being the balancing decisions rather than the strictest controls. The trial does not start on install. The customer can see the real Max tier without a trial key. Reinstalling does not reset the clock. A disabled or artificially slowed validation task cannot freeze Max forever. A temporary network outage is not treated as revocation. A known expiration cannot be extended by pretending the network is down. Premium configuration survives a downgrade. Hosted services reauthorize where the real resource is controlled. Local PHP remains local PHP, with all the limits that implies.

The result is not unbreakable DRM. It was never supposed to be.

It is a division of responsibility. Joomla owns execution on the customer's site. The central service owns the durable facts that should survive a reinstall. The cache keeps the two from becoming unnecessarily dependent on each other for every request. Server-hosted operations make their own authorization decisions. And the customer should keep their data even when their entitlement changes.

That is the question I would leave with another developer or agency: not "how do I stop people from changing my code?" but "which facts should my customer's Joomla site be allowed to decide, and which facts am I willing to operate a service to decide myself?"

If the answer to that second question is "very few," a simple licensing model may be exactly right. If the answer includes trial history, active subscription tiers or expensive hosted resources, then a system like this may be worth the complexity. Either way, thinking about the boundary explicitly is probably more valuable than copying anyone else's licensing scheme.

Sources and further reading

The comparison with other Joomla developers in this article is based only on their publicly documented licensing and subscription behavior as reviewed in September 2026. It is intended to show the range of legitimate commercial models in the ecosystem, not to rank or critique those products. Vendor policies and Joomla Extensions Directory rules can change, so developers should verify current documentation before designing a new distribution or entitlement model.

• Joomla Extensions Directory - The GPL & the JED

• Joomla Extensions Directory - JED Entries Checklists

• Akeeba Backup for Joomla - update and Download ID documentation

• Regular Labs - Extension Manager

• Regular Labs - Terms & Conditions / software licensing

• JoomShaper - SP Page Builder membership and expiration behavior

• StackIdeas - Licensing

• JoomUnited - Joomla Developer Bundle

Internal QuantaCade implementation details were reviewed against the production architecture and converted extension source current on September 23, 2026.