This article explains how Piano detects template types from template HTML, why that detection matters, and why upgrade offer templates must be built with upgrade-specific code. Use it when a template does not appear in Composer, behaves like the wrong offer type, or fails during checkout.
Template type is determined automatically when a template is saved or published. The detected type affects where the template can be used, what runtime data it receives, and which preview options are available in the Template Editor.
How template type detection works
Piano classifies templates by scanning their HTML for specific keywords. The system checks attribute values, attribute names, and element tags. The first matching rule wins, and the scan stops as soon as a match is found.
Detection order matters. If a template contains keywords for more than one type, it is assigned the first matching type in the detection sequence, even if later keywords suggest a different intended use case.
The system checks for the following keywords in this order:
|
Order |
Template type |
Keyword(s) |
Detection notes |
|---|---|---|---|
|
1 |
Zuora offer |
|
Keyword match in content |
|
2 |
Newscycle offer |
|
Keyword match in content |
|
3 |
Default offer (purchase) |
|
Any one of these can classify the template as a purchase offer |
|
4 |
Newsletter signup |
|
Attribute presence detection |
|
5 |
Site Licensing |
|
Attribute presence detection |
|
6 |
Push signup |
|
Keyword match in content |
|
7 |
Piano ID registration |
|
Keyword match in content |
|
8 |
Piano ID custom form |
|
Element tag detection |
|
9 |
Lost value offer (churn) |
|
Both keywords are required |
|
10 |
Final confirmation (churn) |
|
Both keywords are required |
|
11 |
Upgrade offer |
|
Any one of these can classify the template as an upgrade offer |
|
12 |
Session limit |
|
Attribute presence detection |
|
13 |
Default |
No keywords matched |
Generic template fallback |
Piano uses three detection methods:
-
Attribute value detection for most template types
-
Attribute presence detection for newsletter, site licensing, churn prevention, and session limit templates
-
Element tag detection for Piano ID custom form templates
A template that includes both purchase-offer keywords and upgrade-offer keywords will be classified as a purchase offer, because purchase detection runs earlier than upgrade detection.
Why upgrade templates must use the upgrade boilerplate
Purchase offers and upgrade offers are built on different data models.
Purchase offer templates use term-based variables and actions such as terms, selectTerm(), and startCheckout().
Upgrade offer templates use upgrade-option variables and actions such as changeOptions, groupedChangeOptions, and startUpgrade().
Because these models are not interchangeable, a purchase template cannot reliably serve as an upgrade template just by changing the use case in the UI. The underlying HTML still determines the type.
When Composer filters templates for an upgrade offer card, it expects a template that matches both the selected use case and the detected type. If a template was built from a purchase offer boilerplate, it typically contains purchase keywords such as startCheckout(). That causes the backend to classify it as a default purchase offer, so it is filtered out from the upgrade template selector.
Changing the template category or use case to Upgrade offer does not change the detected type. Only changing the template HTML and then saving or publishing the template can trigger re-detection.
Even if a mismatched template is forced into an upgrade experience, it can still fail at runtime. Common symptoms include:
-
Missing upgrade-specific views such as
upgradeSubscription -
Missing components such as
complete-upgrade-component -
Template logic that still references
termsinstead ofchangeOptions -
Errors such as
State upgradeSubscription doesn't existorState offer doesn't exist -
Receipt or confirmation screens that fail during the upgrade flow
How to create a proper upgrade template
The recommended approach is to create the template from an Upgrade offer boilerplate and customize the design from there.
Recommended workflow:
-
Create the template from Manage > Templates > Boilerplates > Upgrade offer.
-
Select one of the default upgrade offer boilerplates.
-
Customize the layout, branding, and styling.
-
Publish the template.
-
Confirm that it appears in the upgrade template selector in Composer.
The boilerplate already includes the required upgrade keywords, views, and components for the expected flow.
Troubleshooting
|
Issue |
Likely cause |
What to check |
Recommended action |
|---|---|---|---|
|
Template does not appear in the Show Offer selector |
Detected type does not match the card's offer type |
Check the template HTML for required keywords and whether save/publish has occurred |
Use the correct boilerplate or update the HTML, then publish again |
|
Template appears but the upgrade flow fails |
Template contains detection keywords but is missing required views or components |
Look for |
Compare the template to the default upgrade boilerplate and add missing sections |
|
Offer selector dropdown is missing in preview |
The editor does not detect the template as an offer type |
Check whether recognized offer keywords are present in the HTML |
Add the required detection keywords and republish |
|
Duplicated template loses its type |
Duplicated content may not preserve the original logic correctly |
Review the duplicated template's HTML and detected behavior |
Correct the HTML and publish again before reuse |
For preview behavior, upgrade keywords alone may not trigger the same offer selector behavior as purchase-offer keywords. If preview options seem incomplete, verify both the detected type and the expected editor behavior for that template category.
Best practices
-
Start from the boilerplate that matches the intended use case.
-
Do not rely on category changes alone to repurpose a template.
-
Keep purchase and upgrade logic separate.
-
After editing template HTML, always save or publish before testing availability in Composer.
-
When troubleshooting, compare the template against a working default boilerplate of the same type.