Search Docs
Loading...
Skip to content

Store Custom Metadata

Attach custom key-value metadata to design blocks in CE.SDK for tracking asset origins, storing application state, or linking to external systems.

5 mins
estimated time
GitHub

Metadata lets you attach arbitrary string key-value pairs to any design block. The data is invisible to end users but persists with the scene through save and load operations. Common use cases include tracking asset origins, storing application-specific state, and linking blocks to external databases or content management systems.

This guide covers how to set, retrieve, list, and remove metadata on blocks, as well as how to store structured data as JSON strings.

Initialize CE.SDK#

We start with a fresh scene that contains a single image block. The metadata APIs live on engine.block and operate on any DesignBlockID, including the scene block itself.

let scene = try engine.scene.create()
let page = try engine.block.create(.page)
try engine.block.setWidth(page, value: 800)
try engine.block.setHeight(page, value: 600)
try engine.block.appendChild(to: scene, child: page)
let imageBlock = try engine.block.create(.graphic)
try engine.block.setShape(imageBlock, shape: engine.block.createShape(.rect))
try engine.block.setWidth(imageBlock, value: 400)
try engine.block.setHeight(imageBlock, value: 300)
try engine.block.setPositionX(imageBlock, value: 200)
try engine.block.setPositionY(imageBlock, value: 150)
let imageFill = try engine.block.createFill(.image)
try engine.block.setString(
imageFill,
property: "fill/image/imageFileURI",
value: "https://img.ly/static/ubq_samples/sample_1.jpg",
)
try engine.block.setFill(imageBlock, fill: imageFill)
try engine.block.appendChild(to: page, child: imageBlock)

Set Metadata#

Use engine.block.setMetadata(_:key:value:) to attach a key-value pair to a block. Both the key and the value are String. If the key already exists, the value is overwritten.

try engine.block.setMetadata(imageBlock, key: "externalId", value: "asset-12345")
try engine.block.setMetadata(imageBlock, key: "source", value: "user-upload")
try engine.block.setMetadata(imageBlock, key: "uploadedBy", value: "user@example.com")

You can attach multiple metadata entries to a single block. Each entry is independent and can be accessed, modified, or removed separately.

Get Metadata#

Use engine.block.getMetadata(_:key:) to retrieve a value by its key. The call throws if the key doesn’t exist, so guard with hasMetadata(_:key:) for conditional access.

if try engine.block.hasMetadata(imageBlock, key: "externalId") {
let externalId = try engine.block.getMetadata(imageBlock, key: "externalId")
print("External ID:", externalId)
}

hasMetadata(_:key:) returns true if the block has metadata for the given key, and false otherwise. This pattern keeps optional reads exception-free.

List All Metadata Keys#

Use engine.block.findAllMetadata(_:) to get every metadata key stored on a block as a [String].

let allKeys = try engine.block.findAllMetadata(imageBlock)
for key in allKeys {
let value = try engine.block.getMetadata(imageBlock, key: key)
print("\(key): \(value)")
}

This is useful for iterating through all metadata on a block or inspecting what is currently attached.

Store Structured Data#

Metadata values must be strings, so encode richer data with JSONEncoder and decode it on read with JSONDecoder. Any Codable type — including a struct local to the function, as shown here — works.

struct GenerationInfo: Codable {
let source: String
let model: String
let timestamp: Int64
}
let info = GenerationInfo(
source: "ai-generated",
model: "stable-diffusion",
timestamp: Int64(Date().timeIntervalSince1970 * 1000),
)
let encoded = try JSONEncoder().encode(info)
try engine.block.setMetadata(
imageBlock,
key: "generationInfo",
value: String(data: encoded, encoding: .utf8)!,
)
let raw = try engine.block.getMetadata(imageBlock, key: "generationInfo")
let decoded = try JSONDecoder().decode(GenerationInfo.self, from: Data(raw.utf8))
print("Generated by \(decoded.model) at \(decoded.timestamp)")

This pattern lets you store generation parameters, configuration objects, or any other structured information that survives a scene save and load.

Remove Metadata#

Use engine.block.removeMetadata(_:key:) to delete a key-value pair from a block. The call throws if the key doesn’t exist, so guard with hasMetadata(_:key:) whenever the key may be absent.

if try engine.block.hasMetadata(imageBlock, key: "uploadedBy") {
try engine.block.removeMetadata(imageBlock, key: "uploadedBy")
}

After removal, you can confirm the key is gone with hasMetadata(_:key:).

let stillHasKey = try engine.block.hasMetadata(imageBlock, key: "uploadedBy")
print("Has uploadedBy after removal:", stillHasKey)
let remainingKeys = try engine.block.findAllMetadata(imageBlock)
print("Remaining metadata keys:", remainingKeys)

Metadata Persistence#

Metadata is preserved when you save a scene with engine.scene.saveToString() or engine.scene.saveToArchive(...). When you load that scene back with engine.scene.load(from:), every metadata entry is restored on its block.

Troubleshooting#

getMetadata Throws#

If getMetadata(_:key:) throws, the key isn’t set on the block. Always pair the call with hasMetadata(_:key:) as shown in the Get Metadata section above.

removeMetadata Throws#

removeMetadata(_:key:) also throws when the key is missing. Guard with hasMetadata(_:key:) before calling it on data that may not be present, or wrap the call in try? if a missing key should be treated as a no-op.

Metadata Lost After Load#

Confirm you’re saving with saveToString() or saveToArchive(...) rather than exporting. Image, video, and PDF exports produce final assets and do not carry metadata.

Large Metadata Values#

Metadata is designed for small strings. Very large values can slow down save and load operations. For large payloads, store a reference (a URL or external ID) instead of the data itself.

API Reference#

MethodDescription
engine.block.setMetadata(_:key:value:)Set a metadata key-value pair on a block
engine.block.getMetadata(_:key:)Get the value for a metadata key
engine.block.hasMetadata(_:key:)Check if a metadata key exists
engine.block.findAllMetadata(_:)List all metadata keys on a block
engine.block.removeMetadata(_:key:)Remove a metadata key-value pair