External Plugins
Adding External Plugins
Last updated January 31, 2026
This guide shows how to add External Plugins (Oracle, AppData) to Core Assets and Collections. Add at creation time or to existing Assets/Collections.
What You'll Learn
- Add external plugins during Asset/Collection creation
- Add external plugins to existing Assets/Collections
- Configure Oracle lifecycle checks
- Set up AppData with data authorities
Summary
Add external plugins using create() with the plugins array, or addPlugin() for existing Assets. Collections use createCollection() and addCollectionPlugin().
- Add at creation: include in
pluginsarray - Add to existing: use
addPlugin()/addCollectionPlugin() - Requires update authority signature
- Configure lifecycle checks for Oracle plugins
Out of Scope
Removing external plugins (see Removing External Plugins), updating plugin data, and built-in plugins (see Adding Plugins).
Quick Start
Jump to: Create Asset with Plugin · Add to Existing Asset · Create Collection with Plugin
- Prepare your Oracle account or AppData configuration
- Add plugin at creation or via
addPlugin() - Configure lifecycle checks (Oracle) or data authority (AppData)
Assets
Creating a Core Asset with an External Plugin
Creating a Core Asset with an External Plugin
import { generateSigner } from '@metaplex-foundation/umi'
import { create, CheckResult } from '@metaplex-foundation/mpl-core'
const assetSigner = publicKey('11111111111111111111111111111111')
const oracleAccount = publicKey('22222222222222222222222222222222')
await create(umi, {
asset: assetSigner,
name: 'My Asset',
uri: 'https://example.com/my-asset.json',
plugins: [
{
type: 'Oracle',
resultsOffset: {
type: 'Anchor',
},
lifecycleChecks: {
update: [CheckResult.CAN_REJECT],
},
baseAddress: oracleAccount,
},
],
}).sendAndConfirm(umi)
Adding a External Plugin to a Core Asset
Adding a Plugin with an assigned authority
use mpl_core::{
instructions::AddExternalPluginAdapterV1Builder,
types::{
ExternalCheckResult, ExternalPluginAdapterInitInfo, HookableLifecycleEvent,
OracleInitInfo, ValidationResultsOffset,
},
};
use solana_client::nonblocking::rpc_client;
use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer, transaction::Transaction};
use std::str::FromStr;
pub async fn add_oracle_plugin_to_asset() {
let rpc_client = rpc_client::RpcClient::new("https://api.devnet.solana.com".to_string());
let authority = Keypair::new();
let asset = Pubkey::from_str("11111111111111111111111111111111").unwrap();
let oracle_plugin = Pubkey::from_str("22222222222222222222222222222222").unwrap();
let add_oracle_plugin_to_asset_ix = AddExternalPluginAdapterV1Builder::new()
.asset(asset)
.payer(authority.pubkey())
.init_info(ExternalPluginAdapterInitInfo::Oracle(OracleInitInfo {
base_address: oracle_plugin,
results_offset: Some(ValidationResultsOffset::Anchor),
lifecycle_checks: vec![(
HookableLifecycleEvent::Transfer,
ExternalCheckResult { flags: 4 },
)],
base_address_config: None,
init_plugin_authority: None,
}))
.instruction();
let signers = vec![&authority];
let last_blockhash = rpc_client.get_latest_blockhash().await.unwrap();
let add_oracle_plugin_to_asset_tx = Transaction::new_signed_with_payer(
&[add_oracle_plugin_to_asset_ix],
Some(&authority.pubkey()),
&signers,
last_blockhash,
);
let res = rpc_client
.send_and_confirm_transaction(&add_oracle_plugin_to_asset_tx)
.await
.unwrap();
println!("Signature: {:?}", res)
}
Collections
Creating a Core Collection with an External Plugin
Adding a External Plugin to a Core Collection
import { generateSigner, publicKey } from '@metaplex-foundation/umi'
import { createCollection, CheckResult } from '@metaplex-foundation/mpl-core'
const collectionSigner = generateSigner(umi)
const oracleAccount = publicKey('22222222222222222222222222222222')
await createCollection(umi, {
collection: collectionSigner,
name: 'My Collection',
uri: 'https://example.com/my-collection.json',
plugins: [
{
type: 'Oracle',
resultsOffset: {
type: 'Anchor',
},
lifecycleChecks: {
update: [CheckResult.CAN_REJECT],
},
baseAddress: oracleAccount,
},
,
],
}).sendAndConfirm(umi)
Adding a External Plugin to a Collection
Burning an Assets
import { publicKey } from '@metaplex-foundation/umi'
import { addCollectionPlugin, CheckResult } from '@metaplex-foundation/mpl-core'
const collection = publicKey('11111111111111111111111111111111')
const oracleAccount = publicKey('22222222222222222222222222222222')
await addCollectionPlugin(umi, {
collection: collection,
plugin: {
type: 'Oracle',
resultsOffset: {
type: 'Anchor',
},
lifecycleChecks: {
update: [CheckResult.CAN_REJECT],
},
baseAddress: oracleAccount,
},
}).sendAndConfirm(umi)
Common Errors
Authority mismatch
Only the update authority can add external plugins. Verify you're signing with the correct keypair.
Plugin already exists
An external plugin with the same key already exists. Remove it first or update it instead.
Invalid Oracle account
The Oracle base address is invalid or the account doesn't exist.
Notes
- External plugins are Authority Managed (update authority controls)
- Oracle plugins require an existing Oracle account
- AppData plugins need a Data Authority for write permissions
- Collection plugins don't automatically apply to existing Assets
FAQ
Can I add multiple external plugins to one Asset?
Yes. You can add multiple Oracle and/or AppData plugins to a single Asset.
Do I need to create the Oracle account first?
Yes. The Oracle account must exist before adding an Oracle plugin adapter.
What's the difference between adding at creation vs adding later?
No functional difference. Adding at creation is more efficient (one transaction). Adding later requires a separate transaction.
Related Operations
- Removing External Plugins - Remove external plugins
- External Plugins Overview - Understanding external plugins
- Oracle Plugin - Oracle configuration details
- AppData Plugin - AppData configuration details
