Shortcuts is a feature that enables both fungible and non-fungible tokens to surface a curated list of links to their holders. Wallets, and other platforms such as NFT marketplaces, can request shortcuts for a given token by querying the external_url
field specified in the token's metadata and appending a /shortcuts.json
path. Shortcuts are hosted and maintained by token creators themselves, and should adhere to the following specification.
shortcuts.mp4
A representation of all possible shortcuts for a given project.
Field | Type | Description |
---|---|---|
version | number | Version of the targeted schema. Current version is 2 . |
shortcuts | array | The list of shortcuts this project supports. |
Example
{
"version": 2,
"shortcuts": []
}
A shortcut object represents a single action that can be performed in a client such as Phantom. It has the following properties:
Field | Type | Description |
---|---|---|
label | string | The suggested text to display on the link |
uri | string | URI pointing to the destination of the shortcut |
type | string | (Optional) The type of token this shortcut applies to. Possible values are fungible or collectible . If omitted, the token will be assumed to be a collectible . |
icon | string | (Optional) The suggested icon to display on the link. The following options are available: vote , vote-2 , stake , stake-2 , view , chat , tip , mint , mint-2 , discord , twitter , x , instagram , telegram , leaderboard , gaming , gaming-2 , generic-link , generic-add |
prefersExternalTarget | boolean | (Optional) Whether the shortcut prefers to be opened outside of the client (e.g. Outside of Phantom's in-app browser). Defaults to false |
preferredPresentation | string | (Optional) How the shortcut prefers to be displayed. Possible values are default and immerse . The platform would choose how that translates to their UX. Defaults to immerse |
limitToCollections | string[] | (Optional) A list of collection addresses that should display this shortcut. Only applicable if type === "collectible" . If provided, the client should only show the shortcut on collections that are in this array. Other collections that share the same external_url will not show this shortcut. Addresses should be provided as strings. Defaults to an empty array [] |
limitToTokenAddresses | string[] | (Optional) A list of token addresses that should display this shortcut. Only applicable if type === "fungible" . If provided, the client should only show the shortcut on tokens that are in this array. Other tokens that share the same external_url will not show this shortcut. Addresses should be provided as strings. Defaults to an empty array [] |
platform | string | (Optional) Indicates to the client that this shortcut should only be displayed for the specified platform. Possible options are desktop , mobile , and all . Defaults to all . |
When designing shortcuts, creators are not limited to static URLs. Instead, creators can specify placeholder variables that can be replaced by a given client. These variables include {{collectionId}}
, {{tokenId}}
, and {{ownerAddress}}
. If you are interested in using more placeholder variables, please let us know by opening an issue on this repository.
Example
{
"label": "Redeem",
"uri": "https://phantom.app/redeem/{{tokenId}}",
"type": "collectible",
"prefersExternalTarget": false,
"icon": "mint"
}
In this example, {{tokenId}}
will be replaced with the on-chain identifier of the token displaying this shortcut.
For use of Shortcuts we request that all creators adhere to the following guidelines:
- Staking
- Socials (Instagram, Twitter/X, Discord, Telegram)
- Messaging features
- Minting
- Tipping
- Voting
- Gaming
Note: If you’d like to do something outside these guidelines, please reach out to us. We are open to evolving these guidelines overtime and want to make sure that we can make Shortcuts successful for your project.
vote
vote-2
stake
stake-2
view
chat
tip
mint
mint-2
discord
twitter
x
instagram
telegram
leaderboard
gaming
gaming-2
generic-link
generic-add
Example
{
"icon": "vote"
}
- All Shortcuts should start with a verb to solidify the action you want the user to take
- Try to use 2-3 word phrases
- Ensure that labels never wrap to a second line
- If the Shortcut isn’t an action (e.g. “Stake” or “Mint”) you can always use “View ____” that way it still starts with a verb
Examples
- “Join [project name] Telegram”
- "Lend on [project name]"
- “Mint NFT”
- “Tip artist”
Projects that want to show shortcuts to their users should ensure that their token(s) have an external_url
present in their metadata. If they do, wallets will be able to fetch the external_url
+ /shortcuts.json
when a user clicks into the token's detail page.
Example
-
NFT metadata’s
external_url
=https://example.com
-
Wallet will request
https://example.com/shortcuts.json
-
Response from
https://example.com/shortcuts.json
looks like:{ "version": 2, "shortcuts": [ { "label": "Tip Artist", "uri": "solana:ART5dr4bDic2sQVZoFheEmUxwQq5VGSx9he7JxHcXNQD?label=Drip+Thanks", "platform": "mobile" }, { "label": "View Artist Page", "uri": "https://drip.haus/degenpoet" }, { "label": "View Vault", "uri": "https://drip.haus/vault" } ] }
In the above example, Phantom would render shortcuts like this 👇
shortcutsguidevid.mp4
💡 Tip: Phantom will respect different paths in addition to the domain. For example, you can have example.com/some-identifier/shortcuts.json
. As long as the NFT has that path in its corresponding external_url
, Phantom will respect it.
The utilization of the external_url
property, as stipulated in current token standards, is recognized by Phantom as potentially hazardous. To ensure the safety of users, Phantom presents a cautionary dialogue when users engage with this property. To bolster security, it's essential to enact several preventive measures.
-
Trusted Tokens: Only query shortcuts for tokens that are neither flagged nor marked as spam. Consider prioritizing tokens that have undergone verification.
-
Allowlist: Introduce an
allowlist.json
containing a pre-defined list of reputable sources. -
Third-Party Verification: Align with verification mechanisms from platforms like Magic Eden and OpenSea. Consider only showing shortcuts on tokens verified by these entities.
-
User Permissions: Consider surfacing an array of user settings such as:
- Allow shortcuts only from partner tokens.
- Allow shortcuts from all tokens.
- Disallow all shortcuts.
Alternatively, provide users with a prompt on every collection page, letting them decide whether to enable shortcuts. This approach offers more granular permissions compared to a universal setting.
-
External Link Restrictions: Only links marked with
prefersExternalTarget
should be permitted to connect to destinations outside of theexternal_url
. -
Proxy Requests: To prevent the unintentional exposure of user IP addresses, all requests should be routed through a proxy. Such a server can also cache responses, mitigating the risk of unintentionally overburdening project servers.
In light of the aforementioned security concerns, Phantom has instituted a rigorous vetting process for all projects. Currently, each project is manually assessed to ensure its alignment with our security standards.
For projects interested in this integration, please complete our Advanced Feature Interest Form.
Composition is the true power of Shortcuts. These are some examples to get you started.
{
"label": "View on instagram",
"uri": "https://instagram.com/famousfoxfed",
"prefersExternalTarget": true
}
To enable experiences that require the user to go into another app or website we recommend using prefersExternalTarget
.
external.mp4
{
"label": "Play now",
"uri": "https://shanksy.xyz/play/{{tokenId}}",
"preferredPresentation": "immerse"
}
By setting a shortcuts's preferredPresentation
to immerse
, developers can take full advantage of the extra available and tailor unique experiences for their users.
immersive-gaming.mp4
{
"label": "Stake",
"uri": "https://famousfoxes.com/stake/{{tokenId}}"
}
Many use cases involve redirecting users to specific features in a dApp. By providing placeholders, platforms can fill in the required information for the dApp to perform their actions.
In this example {{tokenID}}
will be replaced with the collectible id
internal-dapp-feature.mp4
{
"label": "Tip me!",
"uri": "solana:https%3A%2F%2Fsolana-pay-marty-mcflai.vercel.app%2Fapi%3Frecipient%3DEqaavRGuaN4myvgvqs8fMecQ7Y1vGgQUjgZpLsJWG7Nn%26amount%3D0.001%26label%3DKoffii%26reference%3DEqaavRGuaN4myvgvqs8fMecQ7Y1vGgQUjgZpLsJWG7Nn",
"prefersExternalTarget": true,
"platform": "mobile"
}
For a slew of more advanced examples, you can target features that wallets already support. Developers can interact with any property the wallet exposes. To prevent broken experiences, an optional platform modifier can be supplied to limit where the shortcut should be displayed.
solana-pay.mp4
{
"label": "Join chat",
"uri": "https://app.dialect.to/join?id={{tokenId}}",
"prefersExternalTarget": true,
"platform": "mobile"
}
Similar to the Solana pay examples, any Universal Link can be used to generated shortcuts.
Limited to only mobile platforms as Dialect is only supported on mobile as well.
cross-app-integrations.mp4
Projects can partner with providers to do things like loans and provide quick access for users to leverage the partnership
direct-user-to-partner.mp4
Released February 2024.
- Add
type
field that supportsfungible
andcollectible
tokens - Add
limitToTokenAddresses
field forfungible
tokens
Released September 2023.
- Initial specification