Set up a two-surface template workflow where creators build and lock layouts while adopters customize only the areas you allow.
Many integrations need two editing experiences: one for designers or admins who build templates, and one for end users who fill them in. CE.SDK models this with roles and scopes. Use a Creator surface to prepare the template. In production, save that configured template and load it in an Adopter surface; the sample keeps both roles in one scene so it can focus on the permission rules.
The snippets below use the Android Engine API directly. The same role and scope settings are respected by the CE.SDK editor UI; the Design Editor Starter Kit is a complete Android UI surface you can configure around this workflow.
For detailed scope configuration patterns, see Lock Design.
Understanding the Two-Surface Pattern#
Template-based workflows usually split users by responsibility:
| Surface | Users | Role | What they can do |
|---|---|---|---|
| Creator surface | Designers, admins | Creator |
Build templates, set locks, and save the result |
| Adopter surface | End users, marketers | Adopter |
Modify only blocks with enabled scopes |
This separation protects the template’s brand and layout rules while still allowing personalization. The Creator role has full access. The Adopter role applies its default permissions and evaluates block-level scopes.
Setting Up the Creator Surface#
Set the engine role to Creator while building or updating the template. Creators can configure locked brand elements, editable text, and other scope rules before saving the scene.
engine.editor.setRole("Creator")val creatorRole = engine.editor.getRole()
require(creatorRole == "Creator")In an app, this surface can be a dedicated admin screen, a separate editor configuration, or an internal template-building flow.
Configuring What Users Can Edit#
Scopes decide which operations Adopters can perform. In Creator, disable operations on locked blocks and enable only the scopes that should be available on each editable block.
val templateScopes = listOf( "editor/select", "text/edit", "text/character", "fill/change", "layer/move", "layer/resize", "layer/rotate", "lifecycle/destroy",)
listOf(page, background, brandBanner, brandName).forEach { lockedBlock -> templateScopes.forEach { scope -> engine.block.setScopeEnabled(block = lockedBlock, key = scope, enabled = false) }}
engine.block.setScopeEnabled(block = headline, key = "editor/select", enabled = true)engine.block.setScopeEnabled(block = headline, key = "text/edit", enabled = true)engine.block.setScopeEnabled(block = headline, key = "text/character", enabled = false)engine.block.setScopeEnabled(block = headline, key = "fill/change", enabled = false)engine.block.setScopeEnabled(block = headline, key = "layer/move", enabled = false)engine.block.setScopeEnabled(block = headline, key = "layer/resize", enabled = false)engine.block.setScopeEnabled(block = headline, key = "layer/rotate", enabled = false)engine.block.setScopeEnabled(block = headline, key = "lifecycle/destroy", enabled = false)The example keeps the brand banner, background, and brand name locked. The campaign headline can be selected and edited, but it cannot be moved, resized, restyled, or deleted.
Checking Creator Permissions#
After setting block-level scopes, switch back to Creator to confirm the template-building surface still has full access. Creator permissions ignore the locks that constrain Adopters.
engine.editor.setRole("Creator")
val creatorCanSelectBrandBanner = engine.block.isAllowedByScope(brandBanner, key = "editor/select")val creatorCanEditHeadline = engine.block.isAllowedByScope(headline, key = "text/edit")
require(creatorCanSelectBrandBanner)require(creatorCanEditHeadline)This check is useful in tooling that lets designers preview the template before publishing it.
Setting Up the Adopter Surface#
For production surfaces, load the saved template in the end-user surface, then set the role to Adopter. In this sample, the same scene switches to Adopter after scope setup. Because setRole("Adopter") applies the role’s default global scopes, deny editor/add after setting the role when adopters should only edit existing template areas.
engine.editor.setRole("Adopter")engine.editor.setGlobalScope(key = "editor/add", globalScope = GlobalScope.DENY)
val adopterCanAddBlocks = engine.block.isAllowedByScope(headline, key = "editor/add")val adopterCanSelectBrandBanner = engine.block.isAllowedByScope(brandBanner, key = "editor/select")val adopterCanEditHeadline = engine.block.isAllowedByScope(headline, key = "text/edit")val adopterCanRestyleHeadline = engine.block.isAllowedByScope(headline, key = "text/character")val adopterCanMoveHeadline = engine.block.isAllowedByScope(headline, key = "layer/move")val adopterCanDeleteHeadline = engine.block.isAllowedByScope(headline, key = "lifecycle/destroy")
require(!adopterCanAddBlocks)require(!adopterCanSelectBrandBanner)require(adopterCanEditHeadline)require(!adopterCanRestyleHeadline)require(!adopterCanMoveHeadline)require(!adopterCanDeleteHeadline)In this state, users can edit the headline text but cannot add new blocks, select the locked brand banner, or move the headline.
When to Use This Pattern#
Use separate Creator and Adopter surfaces when your integration needs controlled customization:
- Brand template systems: Teams personalize approved layouts without changing brand assets.
- Design approval workflows: Reviewers can inspect a template without accidentally changing protected blocks.
- Self-service customization: Customers edit designated fields inside fixed layout rules.
- White-label products: Tenant-specific surfaces expose only the areas each tenant may change.
For simpler integrations where every user has the same permissions, a single role may be enough.
Viewer Role for Read-Only Access#
For preview or approval screens where no editing should happen, use the Viewer role instead of Adopter.
engine.editor.setRole("Viewer")val viewerRole = engine.editor.getRole()
require(viewerRole == "Viewer")Use Viewer for read-only display. Use Adopter when users should edit selected placeholders, text blocks, or media areas.
Troubleshooting#
| Issue | Cause | Solution |
|---|---|---|
| Adopters can edit everything | The surface is still in Creator, or the locked blocks still have operation scopes enabled |
Set the role to Adopter and disable the relevant block scopes in the Creator surface |
| Adopters cannot select an editable block | editor/select is disabled on that block |
Enable editor/select on every block users should interact with |
| A block is selectable but cannot be changed | The operation-specific scope is disabled | Enable the matching scope, such as text/edit for text content or fill/change for image replacement |
| Adopters can add new blocks | editor/add is still allowed by the Adopter role defaults |
After setting the role to Adopter, set editor/add to GlobalScope.DENY |
| Creator tooling appears locked | The active role is not Creator |
Switch the template-building surface back to Creator before editing locks |
| Template locks do not appear after loading a template | The production template was not saved after configuring scopes | Save the scene/template after setting block scopes in the Creator surface, then load that saved template in the Adopter surface. |
API Reference#
| Method | Purpose |
|---|---|
engine.editor.setRole(role=_) |
Set the active user role, such as Creator, Adopter, or Viewer. |
engine.editor.getRole() |
Read the active user role. |
engine.editor.setGlobalScope(key=_,globalScope=_) |
Allow, deny, or defer an operation globally. |
engine.block.setScopeEnabled(block=_,key=_,enabled=_) |
Enable or disable a scope on one block. |
engine.block.isAllowedByScope(block=_,key=_) |
Check the final permission after role, global scope, and block-level scope evaluation. |
Common Scopes#
| Scope | Description |
|---|---|
editor/add |
Allow adding new blocks. |
editor/select |
Allow selecting the block. |
text/edit |
Allow editing text content. |
text/character |
Allow changing text styling such as font or size. |
fill/change |
Allow changing fill content or text color. |
layer/move |
Allow moving the block. |
layer/resize |
Allow resizing the block. |
layer/rotate |
Allow rotating the block. |
lifecycle/destroy |
Allow deleting the block. |
Next Steps#
- Lock Design - Protect design elements from unwanted modifications
- Editing Workflow - Control editing access with roles and scopes
- Placeholders - Mark editable image, video, or text areas within a locked template layout