# Monitor sync health

Source: https://docs.graphops.xyz/subgraphs/guides/monitor-sync-health

Detect stale data before it reaches your users. Run a small `_meta` query on a schedule, or add
`_meta` to important reads, to see which deployment served the request, how far it has indexed, and
whether it reports indexing errors.

## Prerequisites

* An API key that includes Subgraphs.
* A query endpoint using a Deployment CID, Graph Network Subgraph ID, or Endpoint Alias.
* A place to record health-check results, such as application logs or metrics.
* For lag alerts, a reliable source of the chain head for the same network.

## Request

This request reads `_meta` through an Endpoint Alias: the serving deployment, the indexed block,
and the indexing-error flag.

CLI · curl

Prerequisites

1. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

2. Replace `<ALIAS>` with your Endpoint Alias.

[Example project](/examples/subgraphs.guides.monitor-sync-health.sh-1.tar.gz)

```sh
# `_meta` reports the serving deployment, its latest indexed block, and any indexing errors.
curl --fail-with-body --silent --show-error "https://subgraphs.graphops.xyz/v1/alias/<ALIAS>" \
  -H "Authorization: Bearer ${GRAPHOPS_API_KEY}" \
  -H "Content-Type: application/json" \
  --data '{
    "query": "query SyncHealth { _meta { deployment block { number hash } hasIndexingErrors } }",
    "operationName": "SyncHealth"
  }'

```

Output

```json
{
  "data": {
    "_meta": {
      "deployment": "QmTZ8ejXJxRo7vDBS4uwqBeGoxLSWbhaA7oXa1RvxunLy7",
      "block": {
        "number": 26285621,
        "hash": "0x40c3154aaa484a99057c58a6c72c27171ed861d260179db387850027655d0881"
      },
      "hasIndexingErrors": false
    }
  }
}
```

The deployment that served this request

Highest indexed block; track it over time

Include in support requests

Alert when true

TypeScript · fetch

Prerequisites

1. Install Node.js.

2. Install tsx. `npm install tsx`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

4. Replace `<ALIAS>` with your Endpoint Alias.

Tested with Node.js 24.22.1, tsx 4.23.15.

[Example project](/examples/subgraphs.guides.monitor-sync-health.ts-2.tar.gz)

```typescript
export {};

// `_meta` reports the serving deployment, its latest indexed block, and any indexing errors.
const response = await fetch(
  "https://subgraphs.graphops.xyz/v1/alias/<ALIAS>",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.GRAPHOPS_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: `
        query SyncHealth {
          _meta {
            deployment
            block { number hash }
            hasIndexingErrors
          }
        }
      `,
      operationName: "SyncHealth",
    }),
  },
);
if (!response.ok) throw new Error(await response.text());

const result = await response.json();
console.log(JSON.stringify(result.data._meta));

```

Output

```json
{
  "deployment": "QmTZ8ejXJxRo7vDBS4uwqBeGoxLSWbhaA7oXa1RvxunLy7",
  "block": {
    "number": 26285621,
    "hash": "0x40c3154aaa484a99057c58a6c72c27171ed861d260179db387850027655d0881"
  },
  "hasIndexingErrors": false
}
```

The deployment that served this request

Highest indexed block; track it over time

Include in support requests

Alert when true

Go · net/http

Prerequisites

1. Install Go.

2. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

3. Replace `<ALIAS>` with your Endpoint Alias.

Tested with Go 1.26.0.

[Example project](/examples/subgraphs.guides.monitor-sync-health.go-5.tar.gz)

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"time"
)

func main() {
	// `_meta` reports the serving deployment, its latest indexed block, and any indexing errors.
	payload, err := json.Marshal(struct {
		Query         string `json:"query"`
		OperationName string `json:"operationName"`
	}{
		Query: `
        query SyncHealth {
          _meta {
            deployment
            block { number hash }
            hasIndexingErrors
          }
        }
        `,
		OperationName: "SyncHealth",
	})
	if err != nil {
		log.Fatal(err)
	}

	req, err := http.NewRequest(http.MethodPost,
		"https://subgraphs.graphops.xyz/v1/alias/<ALIAS>", bytes.NewReader(payload))
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("GRAPHOPS_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	resp, err := (&http.Client{Timeout: 30 * time.Second}).Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		log.Fatalf("HTTP %d: %s", resp.StatusCode, body)
	}

	var result struct {
		Data struct {
			Meta json.RawMessage `json:"_meta"`
		} `json:"data"`
	}
	if err := json.Unmarshal(body, &result); err != nil {
		log.Fatal(err)
	}
	var meta bytes.Buffer
	if err := json.Compact(&meta, result.Data.Meta); err != nil {
		log.Fatal(err)
	}
	fmt.Println(meta.String())
}

```

Output

```json
{
  "deployment": "QmTZ8ejXJxRo7vDBS4uwqBeGoxLSWbhaA7oXa1RvxunLy7",
  "block": {
    "number": 26285621,
    "hash": "0x40c3154aaa484a99057c58a6c72c27171ed861d260179db387850027655d0881"
  },
  "hasIndexingErrors": false
}
```

The deployment that served this request

Highest indexed block; track it over time

Include in support requests

Alert when true

Rust · reqwest

Prerequisites

1. Install Rust.

2. Install reqwest, serde\_json, and tokio. `cargo add reqwest serde_json tokio -F reqwest/json -F tokio/macros -F tokio/rt-multi-thread`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

4. Replace `<ALIAS>` with your Endpoint Alias.

Tested with Rust 1.98.1, reqwest 0.13.5, serde\_json 1.0.145, tokio 1.48.0.

[Example project](/examples/subgraphs.guides.monitor-sync-health.rust-6.tar.gz)

```rust
use serde_json::{json, Value};
use std::{env, error::Error, time::Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // `_meta` reports the serving deployment, its latest indexed block, and any indexing errors.
    let response = reqwest::Client::new()
        .post("https://subgraphs.graphops.xyz/v1/alias/<ALIAS>")
        .bearer_auth(env::var("GRAPHOPS_API_KEY")?)
        .timeout(Duration::from_secs(30))
        .json(&json!({
            "query": r#"
        query SyncHealth {
          _meta {
            deployment
            block { number hash }
            hasIndexingErrors
          }
        }
        "#,
            "operationName": "SyncHealth",
        }))
        .send()
        .await?
        .error_for_status()?;
    let result: Value = response.json().await?;
    println!("{}", result["data"]["_meta"]);
    Ok(())
}

```

Output

```json
{
  "block": {
    "hash": "0x40c3154aaa484a99057c58a6c72c27171ed861d260179db387850027655d0881",
    "number": 26285621
  },
  "deployment": "QmTZ8ejXJxRo7vDBS4uwqBeGoxLSWbhaA7oXa1RvxunLy7",
  "hasIndexingErrors": false
}
```

Include in support requests

Highest indexed block; track it over time

The deployment that served this request

Alert when true

Python · requests

Prerequisites

1. Install Python.

2. Install requests. `python -m pip install requests`

3. Set GRAPHOPS\_API\_KEY to your GraphOps API key.

4. Replace `<ALIAS>` with your Endpoint Alias.

Tested with Python 3.12.12, requests 2.34.2.

[Example project](/examples/subgraphs.guides.monitor-sync-health.python-4.tar.gz)

```python
import json
import os

import requests

# `_meta` reports the serving deployment, its latest indexed block, and any indexing errors.
response = requests.post(
    "https://subgraphs.graphops.xyz/v1/alias/<ALIAS>",
    headers={
        "Authorization": f"Bearer {os.environ['GRAPHOPS_API_KEY']}",
    },
    json={
        "query": """
        query SyncHealth {
          _meta {
            deployment
            block { number hash }
            hasIndexingErrors
          }
        }
        """,
        "operationName": "SyncHealth",
    },
    timeout=30,
)
response.raise_for_status()
print(json.dumps(response.json()["data"]["_meta"]))

```

Output

```json
{
  "deployment": "QmTZ8ejXJxRo7vDBS4uwqBeGoxLSWbhaA7oXa1RvxunLy7",
  "block": {
    "number": 26285621,
    "hash": "0x40c3154aaa484a99057c58a6c72c27171ed861d260179db387850027655d0881"
  },
  "hasIndexingErrors": false
}
```

The deployment that served this request

Highest indexed block; track it over time

Include in support requests

Alert when true

## Act on each signal

*Run the same _meta query on a schedule and act on each signal. Check indexing errors first, then the serving deployment, then freshness.*

- `hasIndexingErrors` is true: Alert and check results before you rely on them.
- `deployment` is not the CID you expect: Check the Endpoint Alias target or the owner's latest release.
- `block.number` stops advancing or falls behind your head source: Alert on lag and show freshness to users.
- `block.hash` on every check: Log it with the block number for support requests.

Every response also carries the [`X-Deployment-CID` header](../api#response-headers). Alert when it
changes unexpectedly for an endpoint you expect to stay on one deployment, and record it with each
health-check result.

Compare `_meta.block.number` with the chain head only when you have a reliable head source for the
same network. If `_meta.hasIndexingErrors` is `true`, follow the checks in
[Troubleshooting](../troubleshooting#_metahasindexingerrors-is-true).

Recent blocks can still be corrected by a chain reorganization. See
[Sync and reorgs](../concepts/sync-and-reorgs) before you treat a result as final.

## Next steps

* [Sync and reorgs](../concepts/sync-and-reorgs): Understand indexing lag and when indexed data can change.
* [Manage Endpoint Aliases](./manage-aliases): Check which target an Endpoint Alias serves after a release.
* [Troubleshooting](../troubleshooting): Resolve stale results, indexing errors, and query failures.