Learn how to use Airstack to build General inbox and determine all the users that have a high probability connection with the given user. If they don't qualify, they should be in request inbox
The General inbox should contain all the users that a given user is likely to know or we have strong signals that they are a good actor.
Some criteria that can be checked for a user to be included in the general inbox are:
>X match score on Onchain Graph, which includes:
Sender has non-virtual POAPs in common with the user
Sender has minted >X NFTs in common with the user
Sender has several NFTs in common with the user
People the User follows are following the Sender on Farcaster
People the User follows are following the Sender on Lens
People the User follows have sent the Sender tokens
Senders have ENS and other factors (e.g. ENS + attended non-virtual POAPs)
If the sender doesn't meet the criteria, they should be removed from the main inbox and then placed into the Request Inbox.
Additionally, you can use XMTP Consent to check if a sender has given consent (has an Allowed consent value) to the sender before including them in the primary inbox. By default, you should place all senders that have been given consent directly into the Primary Inbox.
As demonstrated below, your app's interface can also feature user-friendly options for users to apply consent or deny consent. Applying consent should move the user to the Primary Inbox.
Table Of Contents
In this guide, you will learn how to use Airstack to build an XMTP general inbox by:
Airstack provides an AI solution for you to build GraphQL queries to fulfill your use case easily. You can find the AI prompt of each query in the demo's caption or title for yourself to try.
Best Practice
While choosing a specific criteria will significantly decrease the number of spam appearing on your user's XMTP inbox, It is best practice that you combine the multiple criterion given here to build your General Inbox.
This is done to provide multiple layers of filtration that will make it nearly impossible for spammers to have their messages slide into your users' XMTP inbox.
Check If Senders' Onchain Graph Score Above X
To use this criteria, you will NEED TO have a dedicated backend to store user's onchain graph data from Airstack API.
To see if a user's onchain graph score is higher than a specific threshold (for example, value X), your application must already have an onchain graph feature. If it doesn't, follow this tutorial to add one:
After implementing the onchain graph, you'll be able to examine the onchain connections between the user and the senders, assigning scores to each.
Besides the onchain graph score, you can also include other conditions to evaluate these criteria:
Common POAP Events Attended
You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.
You can check if the senders have any common POAP events attended with the user by providing an array of senders' 0x addresses to the $senders variable and the user to the $mainUser variable using the Poaps API:
{"data": {"Poaps": {"Poap": [ {"eventId":"148642","poapEvent": {"poaps": [ {"owner": {"addresses": [// This sender attended the same event as main user"0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab" ] } } ] } }, {"eventId":"149066","poapEvent": {"poaps":null// This POAP has no common attendees } },// Other POAPs ] } }}
Common NFT Collections Minted
You can check if the senders have any common NFT collections minted with the user by taking 2 steps.
First, fetch all the NFT addresses minted by the user by providing the user to the $mainUser variable using the TokenTransfers API:
For this check, you will need a backend to store all the NFT that the user minted
You can update the data on your end periodically to get the data most up to date.
{"data": {"Ethereum": {"TokenTransfer": [ {"tokenAddress":"0xabefbc9fd2f806065b4f3c237d4b59d9a97bcac7" }, {"tokenAddress":"0x0f92612c5f539c89dc379e8aa42e3ba862a34b7e" }, {"tokenAddress":"0x9d90669665607f08005cae4a7098143f554c59ef" }// Other Ethereum NFTs minted by user ] },"Polygon": {},"Base": {},"Zora": {} }}
Once you have the list of NFT addresses from each chain, you can them compile them into an array and provide them as a variable input to the next query along with an array of senders' 0x addresses to the $senders variable to the TokenTransfers API:
You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.
{// All Ethereum NFTs minted"ethereumNfts": ["0xabefbc9fd2f806065b4f3c237d4b59d9a97bcac7","0x0f92612c5f539c89dc379e8aa42e3ba862a34b7e","0x9d90669665607f08005cae4a7098143f554c59ef",// Other Ethereum NFTs minted ],// All Polygon NFTs minted"polygonNfts": ["0x6c6bac0c1adef88f6c35f59181a49bdc78e002f8","0xaef66b056e5daaafc7565700d1f4543b58184b57","0x3d77bbbe0c438db1d3ede544825b7559dddcdb6f",// Other Polygon NFTs minted ],// All Base NFTs minted"baseNfts": ["0x7d5861cfe1c74aaa0999b7e2651bf2ebd2a62d89","0x2a2ca163b4f6806c12f7aad8263ad551ef8ec255","0xba5e05cb26b78eda3a2f8e3b3814726305dcac83".// Other Base NFTs minted ],// No Zora NFTs as the user has no NFT minted in Zora"senders": ["0xB59Aa5Bb9270d44be3fA9b6D67520a2d28CF80AB","0xD7029BDEa1c17493893AAfE29AAD69EF892B8ff2","0x0964256674E42d61f0fF84097E28F65311786ccb" ]}
{"data": {"Ethereum": {"TokenTransfer": [ {"to": {"addresses": [// This sender has the same NFT collection minted as// the user on Ethereum"0xd7029bdea1c17493893aafe29aad69ef892b8ff2" ] } },// Other NFTs minted ] },"Polygon": {"TokenTransfer":null// The senders did not mint anything on Polygon },"Base": {"TokenTransfer": [ {"to": {"addresses": [// This sender has the same NFT collection minted as// the user on Base"0x0964256674e42d61f0ff84097e28f65311786ccb" ] } }, ] } }}
Common NFT Collections Hold
You can check if the senders have any common NFT collections hold with the user by providing an array of senders' 0x addresses to the $senders variable and the user to the $mainUser variable using the TokenBalances API:
You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.
{"data": {"Ethereum": {"TokenBalance": [ {"token": {"tokenBalances": [ {"tokenAddress":"0x95cb845b525f3a2126546e39d84169f1eca8c77f","owner": {"addresses": [// This sender hold a common NFT with the user"0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab" ] } } ] } }, {"token": {"tokenBalances": [] // This NFT is hold by main user, but not the senders } },// Other NFTs on Ethereum ] },// Common NFTs on Polygon"Polygon": {},// Common NFTs on Base"Base": {},// Common NFTs on Zora"Zora": {} }}
Check If The Senders Followed By Those Followed by The User on Lens
For this check, you will need a backend to store the data fetched:
the user's followings on Lens
the addresses that is being followed by the user's followings on Lens
You can update the data on your end periodically to get the data most up to date.
You can check if the senders are is being followed by one of the Lens user followed by the given user on Lens by fetching data from Airstack twice.
First, fetch all the Lens followings of a user by providing the main user to the $mainUser variable using the SocialFollowers API:
Try Demo
Code
queryMyQuery($mainUser: Identity!) { # Get all the user's followers SocialFollowings( input: {filter: {identity: {_eq: $mainUser}, # Only get followers on LensdappName: {_eq: lens} },blockchain: ALL } ) { Following { followingAddress { addresses } } }}
Then, compile the list of users followings and provide it as a variable input to $userFollowings by using the SocialFollowings API:
This query accepts a maximum of 200 wallet inputs to the $userFollowings variable per API call.
Try Demo
Code
queryMyQuery($userFollowers: [Identity!]) { # Get all the Lens followings of the user's followings SocialFollowings( input: {filter: {identity: {_in: $userFollowings}, # Only check on LensdappName: {_eq: lens} },blockchain: ALL } ) { Following { followingAddress { addresses } } }}
{"data": {"SocialFollowings": {"Following": [ {"followingAddress": {"addresses": ["0x2ee5baf1fbaf679b5611fa2b93ae4c752ff62693"] } }, {"followingAddress": {"addresses": ["0x960fd829fbec155f616102f6e654bfab9b9b3ae4"] } }, {"followingAddress": {"addresses": ["0xeaf55242a90bb3289db8184772b0b98562053559"] } }// Other addresses being followed by user's followings on Lens ] } }}
Once you have all these data stored in your backend, you can use it to check whether the sender is one of the addresses that is being followed by the user's followings on Lens.
Check If The Senders Followed By Those Followed by The User on Farcaster
For this check, you will need a backend to store the data fetched:
the user's followings on Farcaster
the addresses that is being followed by the user's followings on Farcaster
You can update the data on your end periodically to get the data most up to date.
You can check if the senders are is being followed by one of the user's followings on Farcaster by fetching data from Airstack twice.
First, fetch all the Farcaster followings of a user by providing the main user to the $mainUser variable using the SocialFollowers API:
Try Demo
Code
queryMyQuery($mainUser: Identity!) { # Get all the user's followings SocialFollowings( input: {filter: {identity: {_eq: $mainUser}, # Only get followings on FarcasterdappName: {_eq: farcaster} },blockchain: ALL } ) { Following { followingAddress { addresses } } }}
Then, compile the list of users followings and provide it as a variable input to $userFollowings by using the SocialFollowings API:
This query accepts a maximum of 200 wallet inputs to the $userFollowings variable per API call.
Try Demo
Code
queryMyQuery($userFollowings: [Identity!]) { # Get all the Farcaster followings of the user's followings SocialFollowings( input: {filter: {identity: {_in: $userFollowings}, # Only check on FarcasterdappName: {_eq: farcaster} },blockchain: ALL } ) { Following { followingAddress { addresses } } }}
{"data": {"SocialFollowings": {"Following": [ {"followingAddress": {"addresses": ["0x66bd69c7064d35d146ca78e6b186e57679fba249","0xeaf55242a90bb3289db8184772b0b98562053559" ] } }, {"followingAddress": {"addresses": ["0x66bd69c7064d35d146ca78e6b186e57679fba249","0xeaf55242a90bb3289db8184772b0b98562053559" ] } }// Other addresses being followed by user's followers on Farcaster ] } }}
Once you have all these data stored in your backend, you can use it to check whether the sender is one of the addresses that is being followed by the user's followings on Farcaster.
Check If Any of The User's Followers on Lens or Farcaster Sent Any Token To The Sender
You can check if the senders are is being followed by one of the user's followers on Farcaster by fetching data from Airstack twice.
First, fetch all the Lens and Farcaster followers of a user by providing the main user to the $mainUser variable using the SocialFollowers API:
For this check, you will need a backend to store the user's followers on Lens and Farcaster.
You can update the data on your end periodically to get the data most up to date.
Try Demo
Code
queryMyQuery($mainUser: Identity!) { # Get all the user's followers SocialFollowers( input: {filter: {identity: {_eq: $mainUser} },blockchain: ALL } ) { Follower { followerAddress { addresses } } }}
Then, compile the list of users followers and provide it as a variable input to $userFollowers along with the senders' 0x address to the $senders variable by using the TokenTransfers API:
You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.
Try Demo
Code
queryMyQuery( $userFollowers: [Identity!], $senders: [Identity!]) { # Check for any Ethereum Token TransfersEthereum: TokenTransfers( input: {filter: {from: {_in: $userFollowers},to: {_in: $senders} },blockchain: ethereum } ) { TokenTransfer { to { addresses } } } # Check for any Polygon Token TransfersPolygon: TokenTransfers( input: {filter: {from: {_in: $userFollowers},to: {_in: $senders} },blockchain: polygon } ) { TokenTransfer { to { addresses } } } # Check for any Base Token TransfersBase: TokenTransfers( input: {filter: {from: {_in: $userFollowers},to: {_in: $senders} },blockchain: base } ) { TokenTransfer { to { addresses } } } # Check for any Zora Token TransfersZora: TokenTransfers( input: {filter: {from: {_in: $userFollowers},to: {_in: $senders} },blockchain: zora } ) { TokenTransfer { to { addresses } } }}
{"data": {"Ethereum": {"TokenTransfer": [ {"to": {"addresses": [// This sender has received token transfer// from one of the user's follower"0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab" ] } },// Other token transfers on Ethereum ] },"Polygon": {"TokenTransfer":null },"Base": {"TokenTransfer":null },"Zora": {"TokenTransfer":null } }}
Check If XMTP Users Have Any ENS and Attended Any Non-Virtual POAPs
You can check if senders has any ENS and attended any non-virtual POAPs by providing the senders' 0x address to the $senders variable using the Poaps API:
You can use this query to filter senders on the fly with a maximum of 200 wallet inputs to the $senders variable per API call.
{"data": {"Domains": {"Domain": [ {"name":"dawufi.eth","owner":"0x0964256674e42d61f0ff84097e28f65311786ccb","ownerDetails": {"poaps": [ {"poapEvent": {"isVirtualEvent":false,// This is non-virtual POAP"eventName":"Skyteller x Consensus 2023","eventId":"124226" } },// Other POAPs ] } },// Other ENS domain that is owned by the sender ] } }}
Developer Support
If you have any questions or need help regarding building your general inbox on your XMTP messaging app, please join our Airstack's Telegram group.