Guide / ~6 min read

Querying with GraphQL

Search and filter transactions by tags, owners, and metadata using Arweave's GraphQL endpoints.

Querying with GraphQL
Permanent on Arweave

Arweave gateways expose a GraphQL endpoint that lets you search, filter, and retrieve transactions by tags, owners, recipients, block height, and more. This is the primary way to discover and index data on the permaweb.

The GraphQL Endpoint

Every Arweave gateway provides a GraphQL endpoint:

https://arweave.net/graphql

Alternative endpoints for reliability:

  • https://arweave-search.goldsky.com/graphql (Goldsky indexer)
  • https://g8way.io/graphql (alternative gateway)

Basic Query

Here's a query that fetches the 10 most recent transactions:

query {
  transactions(first: 10, sort: HEIGHT_DESC) {
    edges {
      node {
        id
        owner {
          address
        }
        tags {
          name
          value
        }
        block {
          height
          timestamp
        }
      }
    }
  }
}

Filtering by Tags

Tags are the primary way to find specific data on Arweave. Every transaction can have up to 2 KB of key-value tag metadata, and all of it is queryable.

Find HTML Content

query {
  transactions(
    tags: [
      { name: "Content-Type", values: ["text/html"] }
    ]
    first: 10
  ) {
    edges {
      node {
        id
        tags {
          name
          value
        }
      }
    }
  }
}

Find Transactions from a Specific App

query {
  transactions(
    tags: [
      { name: "App-Name", values: ["My-App"] },
      { name: "App-Version", values: ["1.0.0"] }
    ]
    first: 20
  ) {
    edges {
      node {
        id
        owner { address }
        block { timestamp }
      }
    }
  }
}

Multiple tag filters use AND logic, so all conditions must match.

Filtering by Owner

Find all transactions from a specific wallet address:

query {
  transactions(
    owners: ["M6w588ZkR8SVFdPkNXdBy4sqbMN0Y3F8ZJUWm2WCm8M"]
    first: 10
  ) {
    edges {
      node {
        id
        tags {
          name
          value
        }
      }
    }
  }
}

Filtering by Block Height

Useful for finding transactions within a specific time range:

query {
  transactions(
    block: { min: 587540, max: 587550 }
    first: 100
  ) {
    edges {
      node {
        id
        block {
          height
          timestamp
        }
      }
    }
  }
}

Pagination with Cursors

For large result sets, use cursor-based pagination:

query {
  transactions(first: 10, after: "WyIyMDIzLTAxLTAxVDAwOjAwOjAwLjAwMFoiLDFd") {
    pageInfo {
      hasNextPage
    }
    edges {
      cursor
      node {
        id
      }
    }
  }
}

Use the cursor value from the last edge as the after parameter in the next query.

Using ar-gql (JavaScript Library)

The ar-gql library simplifies GraphQL queries from JavaScript:

Install

npm install ar-gql

Query Transactions

import { arGql } from 'ar-gql';

const gql = arGql();

// Find transactions by tag
const results = await gql.run(`
  query {
    transactions(
      tags: [
        { name: "App-Name", values: ["My-App"] }
      ]
      first: 10
    ) {
      edges {
        node {
          id
          owner { address }
          tags { name value }
        }
      }
    }
  }
`);

for (const edge of results.data.transactions.edges) {
  console.log('TX:', edge.node.id);
  console.log('Owner:', edge.node.owner.address);
}

Paginate Automatically

const allResults = [];
let hasNextPage = true;
let cursor = '';

while (hasNextPage) {
  const query = `query($cursor: String) {
    transactions(
      tags: [{ name: "App-Name", values: ["My-App"] }]
      first: 100
      after: $cursor
    ) {
      pageInfo { hasNextPage }
      edges {
        cursor
        node { id }
      }
    }
  }`;

  const result = await gql.run(query, { cursor });
  const edges = result.data.transactions.edges;

  allResults.push(...edges.map(e => e.node));
  hasNextPage = result.data.transactions.pageInfo.hasNextPage;
  cursor = edges[edges.length - 1]?.cursor || '';
}

Reading Transaction Data

Once you have a transaction ID, fetch its data directly:

// Via gateway HTTP
const response = await fetch(`https://arweave.net/${txId}`);
const data = await response.text();

// Via Arweave JS
import Arweave from 'arweave';
const arweave = Arweave.init({ host: 'arweave.net', port: 443, protocol: 'https' });
const data = await arweave.transactions.getData(txId, { decode: true, string: true });

Common Tag Patterns

Applications on Arweave use standardized tags for interoperability:

Tag Purpose Example
Content-Type MIME type for rendering text/html, image/png
App-Name Application identifier My-App
App-Version Version tracking 1.0.0
Type Content classification post, profile, comment
Title Human-readable title My First Post
Unix-Time Timestamp (seconds) 1704067200
Topic Content categorization arweave, development

Using consistent tags ensures your data is discoverable by other applications. This is what makes Arweave a shared, interoperable data layer rather than isolated storage.

Subscribe to our newsletter

Built by the Arweave community

Permanently hosted on Arweave