⚠️Blast API (blastapi.io) ends Oct 31. Migrate to Dwellir and skip Alchemy's expensive compute units.
Switch Today →
Skip to main content

Coming soon: Need support for this? Email support@dwellir.com and we will enable it for you.

Token Activities

Token activities tracking provides comprehensive visibility into NFT and token operations on Aptos, including mints, transfers, burns, and marketplace interactions. The GraphQL API enables querying of activity histories, ownership changes, and collection analytics essential for NFT marketplaces, portfolio trackers, and blockchain explorers.

Overview#

Every NFT interaction on Aptos generates events that are indexed and made queryable through GraphQL. Token activities encompass all operations affecting digital assets - from initial minting through transfers, sales, and eventual burning. This data enables applications to display transaction histories, track provenance, analyze trading patterns, and provide real-time notifications for NFT-related events.

Core Query Patterns#

User Activity History#

query TokenTransfers($owner: String!, $limit: Int!) {
token_activities_v2(
where: { owner_address: { _eq: $owner } },
limit: $limit,
order_by: { transaction_version: desc }
) {
transaction_version
event_account_address
token_standard
from_address
to_address
token_data_id
amount
type
transaction_timestamp
token_data {
token_name
collection_id
current_collection {
collection_name
creator_address
}
}
}
}

Collection Activity Feed#

query CollectionActivities($collection_id: String!, $limit: Int!) {
token_activities_v2(
where: {
token_data: {
collection_id: { _eq: $collection_id }
}
},
order_by: { transaction_version: desc },
limit: $limit
) {
type
from_address
to_address
token_data_id
transaction_timestamp
transaction_version
}
}

Recent Mints#

query RecentMints($collection_id: String!) {
token_activities_v2(
where: {
type: { _eq: "0x4::token::MintEvent" },
token_data: {
collection_id: { _eq: $collection_id }
}
},
order_by: { transaction_version: desc },
limit: 50
) {
to_address
token_data_id
transaction_timestamp
transaction_version
}
}

Sales and Transfers#

query TokenSales($token_data_id: String!) {
token_activities_v2(
where: {
token_data_id: { _eq: $token_data_id },
type: { _in: ["0x4::token::TransferEvent", "marketplace_sale"] }
},
order_by: { transaction_version: desc }
) {
type
from_address
to_address
transaction_version
transaction_timestamp
event_account_address
}
}

Burn Events#

query BurnedTokens($collection_id: String!) {
token_activities_v2(
where: {
type: { _eq: "0x4::token::BurnEvent" },
token_data: {
collection_id: { _eq: $collection_id }
}
},
order_by: { transaction_version: desc }
) {
token_data_id
from_address
transaction_timestamp
}
}

Real-World Use Cases#

  1. NFT Marketplaces: Display comprehensive activity feeds showing mints, listings, sales, and transfers for collections and individual NFTs with real-time updates.

  2. Portfolio Trackers: Show users their complete NFT transaction history including acquisitions, sales, transfers, and current holdings across all collections.

  3. Collection Analytics: Analyze trading volumes, mint rates, holder behavior, and price trends for NFT collections to provide market intelligence.

  4. Provenance Tracking: Build complete ownership histories showing every transfer from mint to current owner for authenticity verification.

  5. Notification Systems: Alert users instantly when their NFTs are transferred, listed, sold, or when new items mint in collections they follow.

  6. Marketplace Aggregators: Combine activity data from multiple marketplaces to provide comprehensive views of NFT trading across the ecosystem.

Best Practices#

Filter by Activity Type: Use the type field to distinguish between mints, transfers, burns, and marketplace events for appropriate handling.

Paginate Results: Implement cursor-based pagination for activity feeds to efficiently handle collections with high volumes of transactions.

Join with Token Data: Always join activities with token_data to fetch metadata (names, images, attributes) for display.

Cache Collection Metadata: Collection-level data changes rarely - cache it aggressively to reduce duplicate queries.

Handle Missing Data: Not all activities have complete metadata - implement fallbacks for missing names, images, or attributes.

Time-Based Filtering: Use transaction_timestamp for date range queries when analyzing historical trends or generating reports.

Aggregate for Statistics: Use aggregate queries to compute volumes, counts, and other metrics rather than client-side processing.

TypeScript Integration#

import { ApolloClient, gql } from "@apollo/client";

const client = new ApolloClient({
uri: "https://api-aptos-mainnet.n.dwellir.com/YOUR_API_KEY/v1/graphql"
});

interface TokenActivity {
type: string;
fromAddress: string;
toAddress: string;
tokenDataId: string;
timestamp: string;
tokenName: string;
collectionName: string;
}

async function getActivityFeed(address: string, limit: number = 50): Promise<TokenActivity[]> {
const { data } = await client.query({
query: gql`
query ActivityFeed($address: String!, $limit: Int!) {
token_activities_v2(
where: {
_or: [
{ from_address: { _eq: $address } },
{ to_address: { _eq: $address } }
]
},
order_by: { transaction_version: desc },
limit: $limit
) {
type
from_address
to_address
token_data_id
transaction_timestamp
token_data {
token_name
current_collection {
collection_name
}
}
}
}
`,
variables: { address, limit }
});

return data.token_activities_v2.map((activity: any) => ({
type: activity.type,
fromAddress: activity.from_address,
toAddress: activity.to_address,
tokenDataId: activity.token_data_id,
timestamp: activity.transaction_timestamp,
tokenName: activity.token_data?.token_name || "Unknown",
collectionName: activity.token_data?.current_collection?.collection_name || "Unknown"
}));
}

// Format activity for display
function formatActivity(activity: TokenActivity): string {
if (activity.type.includes("Mint")) {
return `Minted ${activity.tokenName}`;
} else if (activity.type.includes("Transfer")) {
return `Transferred ${activity.tokenName} from ${activity.fromAddress.substring(0, 6)}... to ${activity.toAddress.substring(0, 6)}...`;
} else if (activity.type.includes("Burn")) {
return `Burned ${activity.tokenName}`;
}
return `${activity.type} - ${activity.tokenName}`;
}

Advanced Queries#

Collection Trading Volume#

query TradingVolume($collection_id: String!, $since: timestamp!) {
token_activities_v2_aggregate(
where: {
token_data: {
collection_id: { _eq: $collection_id }
},
type: { _in: ["marketplace_sale", "0x4::token::TransferEvent"] },
transaction_timestamp: { _gte: $since }
}
) {
aggregate {
count
}
}

activities: token_activities_v2(
where: {
token_data: {
collection_id: { _eq: $collection_id }
},
type: { _in: ["marketplace_sale"] },
transaction_timestamp: { _gte: $since }
},
order_by: { transaction_timestamp: desc }
) {
transaction_timestamp
from_address
to_address
token_data_id
}
}

Most Active Traders#

query ActiveTraders($collection_id: String!, $days: Int!) {
token_activities_v2(
where: {
token_data: {
collection_id: { _eq: $collection_id }
},
transaction_timestamp: { _gte: "now() - ${days} days" }
},
distinct_on: from_address
) {
from_address
}
}

Token Provenance Chain#

query TokenHistory($token_data_id: String!) {
token_activities_v2(
where: { token_data_id: { _eq: $token_data_id } },
order_by: { transaction_version: asc }
) {
type
from_address
to_address
transaction_version
transaction_timestamp
event_account_address
}
}

Activity Type Classification#

Common activity types and their meanings:

  • 0x4::token::MintEvent: NFT was minted
  • 0x4::token::TransferEvent: NFT was transferred
  • 0x4::token::BurnEvent: NFT was burned/destroyed
  • marketplace_listing: NFT was listed for sale
  • marketplace_sale: NFT was sold
  • marketplace_delist: Listing was cancelled

Pagination Pattern#

async function getPaginatedActivities(
address: string,
limit: number,
offset: number
): Promise<TokenActivity[]> {
const { data } = await client.query({
query: gql`
query PaginatedActivities($address: String!, $limit: Int!, $offset: Int!) {
token_activities_v2(
where: { owner_address: { _eq: $address } },
order_by: { transaction_version: desc },
limit: $limit,
offset: $offset
) {
# fields...
}
}
`,
variables: { address, limit, offset }
});

return data.token_activities_v2;
}