External Plugins
AppData Plugin
Last updated January 31, 2026
The AppData Plugin provides secure, partitioned data storage on Core Assets. Third-party applications can store and read arbitrary data (JSON, MsgPack, or binary) with exclusive write access controlled by a Data Authority.
What You'll Learn
- Add AppData to Assets and Collections
- Configure Data Authorities for secure writes
- Choose data schemas (JSON, MsgPack, Binary)
- Read and write data from on-chain and off-chain
Summary
The AppData plugin stores arbitrary data on Assets with controlled write access. Only the Data Authority can write to the plugin's data section, enabling secure third-party integrations.
- Store JSON, MsgPack, or Binary data
- Data Authority has exclusive write permission
- Automatically indexed by DAS (JSON/MsgPack)
- LinkedAppData variant for collection-wide writes
Out of Scope
Oracle validation (see Oracle Plugin), on-chain attributes (see Attributes Plugin), and off-chain metadata storage.
Quick Start
Jump to: Add to Asset · Write Data · Read Data
- Add AppData plugin with a Data Authority address
- Choose schema: JSON, MsgPack, or Binary
- Write data using
writeData()(must sign as Data Authority) - Read data via DAS or direct account fetch
What is an AppData Plugin?
The AppData external plugin stores and contains arbitrary data that can be written to by the dataAuthority. Note this is different then the overall plugin authority stored in the ExternalRegistryRecord as it cannot update/revoke authority or change other metadata for the plugin. Think of AppData as like a partition data area of an Asset that only a certain authority can change and write to. This is useful for 3rd party sites/apps to store data needed to execute certain functionality within their product/app.
Works With
| MPL Core Asset | ✅ |
| MPL Core Collection* | ✅ |
* MPL Core Collections can also work with the LinkedAppData Plugin. |
What is a LinkedAppData Plugin?
The LinkedAppData plugin is built for Collections. It allows you to add a single plugin adapter on the collection which will allow you to write to any Asset in the collection.
Arguments
| Arg | Value |
|---|---|
| dataAuthority | PluginAuthority |
| schema | ExternalPluginAdapterSchema |
dataAuthority
AttributeList
const dataAuthority = {
type: 'Address',
address: publicKey('11111111111111111111111111111111'),
}
schema
The schema determines the type of data that is being stored within the AppData plugin. All schemas will be indexed by DAS.
| Arg | DAS Supported | Stored as |
|---|---|---|
| Binary (Raw Data) | ✅ | base64 |
| Json | ✅ | json |
| MsgPack | ✅ | json |
When indexing the data if there was an error reading the JSON or MsgPack schema then it will be saved as binary. |
Writing data to the `AppData` plugin
import { ExternalPluginAdapterSchema } from '@metaplex-foundation/mpl-core'
// Chose from Binary, Json or MsgPack
const schema = ExternalPluginAdapterSchema.Json
Adding the AppData Plugin to an Asset
Adding a Attribute Plugin to an MPL Core Asset
import { publicKey } from '@metaplex-foundation/umi'
import { addPlugin, ExternalPluginAdapterSchema } from '@metaplex-foundation/mpl-core'
const assetSigner = generateSigner(umi);
const dataAuthority = publicKey('11111111111111111111111111111111')
await create(umi, {
asset: asset.publicKey,
name: "My Asset",
uri: "https://example.com/my-assets.json"
plugins: [
{
type: 'AppData',
dataAuthority,
schema: ExternalPluginAdapterSchema.Json,
},
],
}).sendAndConfirm(umi)
// Alternatively you could add the plugin to an existing Asset
await addPlugin(umi, {
asset,
plugin: {
type: 'AppData',
dataAuthority,
schema: ExternalPluginAdapterSchema.Json,
},
})
Writing Data to the AppData Plugin
Only the dataAuthority address can write data to the AppData plugin. To write data to the AppData plugin we will use a writeData() helper which takes the following args.
| Arg | Value |
|---|---|
| key | { type: string, dataAuthority: publicKey} |
| authority | signer |
| data | data in the format you wish to store |
| asset | publicKey |
Serializing JSON
Serializing JSON
const json = {
timeStamp: Date.now(),
message: 'Hello, World!',
}
const data = new TextEncoder().encode(JSON.stringify(json))
Serializing MsgPack
Serializing MsgPack
// This implementation uses `msgpack-lite` for serialization
const json = {
timeStamp: Date.now(),
message: 'Hello, World!',
}
const data = msgpack.encode(json)
Serializing Binary
As binary can store arbitrary data it's up to you to decide on how you are going to serialize and deserialize the data.
Serializing Binary
// The below example is just creating bytes that are considered `true` or `false`.
const data = new Uint8Array([1, 0, 0, 1, 0])
Writing Data
Adding a Attribute Plugin to an MPL Core Asset
await writeData(umi, {
key: {
type: 'AppData',
dataAuthority,
},
authority: dataAuthoritySigner,
data: data,
asset: asset.publicKey,
}).sendAndConfirm(umi)
Reading Data from the AppData Plugin
Data can be both read on chain programs and external sources pulling account data.
Fetch the Raw Data
The first step to deserializing the data stored in an AppData plugin is to fetch the raw data and check the schema field which dictates the format in which the data is stored before serialization.
Fetching `AppData` Raw Data
const assetId = publicKey('11111111111111111111111111111111')
const dataAuthority = publicKey('33333333333333333333333333333333')
const asset = await fetchAsset(umi, assetId)
let appDataPlugin = asset.appDatas?.filter(
(appData) => (appData.authority.address = dataAuthority)
)
let data
let schema
// Check if `AppData` plugin with the given authority exists
if (appDataPlugin && appDataPlugin.length > 0) {
// Save plugin data to `data`
data = appDataPlugin[0].data
// Save plugin schema to `schema`
schema = appDataPlugin[0].schema
}
Deserialization
Now that you have the data you'll need to deserialize the data depending on the schema you chose to write the data with to the AppData plugins.
Deserialize JSON Schema
Deserializing JSON
// Due to the JS SDK, the deserialization for the MsgPack schema is automatic and deserialized
// data can be accessed at the RAW location example above.
Deserialize MsgPack Schema
Deserializing MsgPack
// Due to the JS SDK, the deserialization for the MsgPack schema is automatic and deserialized
// data can be accessed at the RAW location example above.
Deserialize Binary Schema
Because the Binary schema is arbitrary data then deserialization will be dependent on the serialization you used.
Deserializing Binary
// As the binary data is arbitrary you will need to include your own deserializer to
// parse the data into a usable format your app/website will understand.
Common Errors
Authority mismatch
Only the Data Authority can write data. Verify you're signing with the correct keypair.
Data too large
The data exceeds account size limits. Consider compressing or splitting data across multiple plugins.
Invalid schema
The data doesn't match the declared schema. Ensure JSON is valid or MsgPack is properly encoded.
Notes
- Data Authority is separate from plugin authority
- Choose JSON or MsgPack for DAS indexing
- Binary schema for custom serialization formats
- LinkedAppData allows writing to any Asset in a Collection
Quick Reference
Schema Comparison
| Schema | DAS Indexed | Best For |
|---|---|---|
| JSON | ✅ As JSON | Human-readable, web apps |
| MsgPack | ✅ As JSON | Compact, typed data |
| Binary | ✅ As base64 | Custom formats, max efficiency |
AppData vs Attributes Plugin
| Feature | AppData | Attributes |
|---|---|---|
| Write permission | Data Authority only | Update Authority |
| Data format | Any (JSON, MsgPack, Binary) | Key-value strings |
| Third-party friendly | ✅ Yes | ❌ Requires update authority |
| DAS indexing | ✅ Yes | ✅ Yes |
FAQ
What's the difference between AppData and the Attributes plugin?
Attributes stores key-value strings controlled by the update authority. AppData stores arbitrary data controlled by a separate Data Authority, making it ideal for third-party applications.
Can I have multiple AppData plugins on one Asset?
Yes. Each AppData plugin can have a different Data Authority, allowing multiple third-party apps to store data on the same Asset.
How do I update existing AppData?
Call writeData() with the new data. This replaces the existing data entirely—there's no partial update.
Is AppData indexed by DAS?
Yes. JSON and MsgPack schemas are automatically deserialized and indexed. Binary is stored as base64.
What is LinkedAppData?
LinkedAppData is added to a Collection and allows the Data Authority to write to any Asset in that Collection without adding AppData to each Asset individually.
Glossary
| Term | Definition |
|---|---|
| AppData | External plugin for storing arbitrary data on Assets |
| Data Authority | Address with exclusive write permission |
| LinkedAppData | Collection-level variant for writing to any Asset |
| Schema | Data format: JSON, MsgPack, or Binary |
| writeData() | Function to write data to AppData plugin |
Related Pages
- External Plugins Overview - Understanding external plugins
- Oracle Plugin - Validation instead of data storage
- Attributes Plugin - Built-in key-value storage
- On-chain Ticketing Guide - AppData example
