

How to Pause Queries on Inactive Browser Tabs Using Graph-Client
Introduction
In this blog post we will discuss one of the most effective ways in which you can optimize the amount of queries to The Graph Network from within your dapp – effectively reducing instances in which unneeded queries are made. Following this guide will also optimize your applications performance by implementing a real time data fetching pattern.
One important factor you should consider when querying a subgraph is how often the data changes. As an example, the Ethereum network creates a new block about every 12 seconds. Therefore if your application is fetching data every second, you can assume that in most cases 11 out of those 12 requests are wasted. Additionally, if you want a good user experience for your application, you want the data to update automatically and if they tab away from your page and come back, you don’t want them to have to refresh the page, but rather automatically start pulling the data they need in the UI.
The good news is that both of these key objectives can be achieved by enabling real-time data queries (live queries) and limiting data streaming to only active browser tabs, both of which are powerful features of .
The below steps will walk through an example implementation, which can be found in this .
Setup
In this example we will use NextJS. If you need instructions on how to set up a NextJS project read the following to get started quickly.
Once you have a project setup, you will need to install `@graphprotocol/client-cli`, `@graphprotocol/client-polling-live` and . To install graph-cli and client-polling-live run the following with the package manager of your choice.
yarn:
yarn add -D @graphprotocol/client-cli @graphprotocol/client-polling-live
npm:
npm install --save-dev @graphprotocol/client-cli @graphprotocol/client-polling-live
Configuration
To enable live queries, add the following to your `` configuration file. You can set the defaultInterval to whatever you prefer, the default value for `defaultInterval` is `1000`. The interval can also be configured on individual queries if it’s preferred. Since we will be querying an Ethereum subgraph, setting the interval to 11000 milliseconds (11 seconds) will align with the frequency of new blocks.
plugins:- pollingLive:defaultInterval: 11000
The is a good example of an active subgraph that gets new data frequently. To configure Graph Client to use this subgraph, create a `.graphclientrc.yml` and define the `sources.name` as mainnet along with the `handler.graphql.endpoint`. You will need to replace the `<APIKEY>` in the url with your own API key. You can generate an API key on The Graph website under the section of Subgraph Studio.
# .graphclientrc.ymlsources:- name: mainnethandler:graphql:endpoint: https://gateway-arbitrum.network.thegraph.com/api/<APIKEY>/subgraphs/id/HUZDsRpEVP2AvzDCyzDHtdc64dyDxx8FQjzsmqSg4H3B
A best practice is to store your GraphQL queries in a dedicated directory. To do this, add the documents configuration to the `.graphclientrc.yml` configuration. In the below example all files with the extension `.graphql` will be loaded from the `queries` folder.
documents:- "./queries/*.graphql"
In this example we have a query file named ``. In that query the `@live` parameter will tell Graph Client to query for real-time data.
query MyQuery @live {transactions(first: 1, orderBy: timestamp, orderDirection: desc) {swaps(first: 1) {amountUSDamount0amount1pool {token1 {name}token0 {name}}}}}
After you’ve created the query, you will need to generate the unified schema, artifacts and `index.tsx` file. To do this run `yarn graphclient build`
yarn run v1.22.21$ /Users/crashoverride/my-app/node_modules/.bin/graphclient build💡 GraphClient Cleaning existing artifacts💡 GraphClient Reading the configuration💡 GraphClient Generating the unified schema💡 GraphClient Generating artifacts💡 GraphClient Generating index file in TypeScript💡 GraphClient Writing index.ts for ESM to the disk.💡 GraphClient Cleanup💡 GraphClient Done! => /Users/kevinjones/my-app/.graphclient✨ Done in 2.87s.
If you would like to test your Graph Client configuration. You can load the Yoga GraphiQL server by running `yarn graphclient serve-dev`. This will launch the GraphiQL in a new browser window. Add the query from above and click the Execute Query button.
As you can see in the examples a live query response contains an additional boolean key named `isLive` and the data will refresh automatically based on the configuration. Below you can see the full payload response.
{"data": {"transactions": [{"swaps": [{"amount0": "-536.190827804100513073","amount1": "0.402278485649731011","amountUSD": "1288.501022062263933522516181107626","pool": {"token0": {"name": "Safe Token"},"token1": {"name": "Wrapped Ether"}}}]}]},"isLive": true}
Next, add set `pauseOnBackground` to true so that only active browser sessions will perform live queries. The default value for this directive is `true`, however it is recommended to explicitly define it for anyone reviewing the configuration will know the behavior of your application.
plugins:- pollingLive:defaultInterval: 10000pauseOnBackground: true
Frontend Configuration
After the configuration of Graph Client is complete, the next step is to configure the frontend application to subscribe to the live queries. A full example of this code can be found in the project’s main page under ``. Let’s walk through the frontend configuration. First, import all the types and hooks needed to render the page properly.
import { useEffect, useState } from "react";import type { NextPage } from "next";import { MyQueryDocument,MyQueryQuery,subscribe} from "../.graphclient";import { ExecutionResult } from "graphql";
The most notable configuration changes here are the imports of the types that were generated earlier using Graph Client CLI along with the type definitions from the GraphQL library.
Next, within the Next application you will fetch the data, since this is a live query the configuration should use the `subscribe()` function to fetch the data we need in our application.
const [result, setResult] = useState<ExecutionResult<MyQueryQuery> | null>(null);useEffect(() => {let shouldContinue = true;const fetchData = async () => {try {const fetchedResult = await subscribe(MyQueryDocument, {});if ("data" in fetchedResult) {if (shouldContinue) {setResult(fetchedResult);}} else {for await (const result of fetchedResult) {if (!shouldContinue) break;setResult(result);}}} catch (error) {console.error("Failed to fetch data:", error);}};fetchData();return () => {shouldContinue = false;};}, []);
Lastly, the data can be rendered in the return statement. In the below example we use `.map` to build a dynamic list of items. This is here as an example implementation but would need to be custom based on your query results.
return (<><div className="flex items-center flex-col flex-grow pt-10"><div className="px-5"><h1 className="text-center"><span className="block text-4xl font-bold">Query The Graph</span></h1></div><div className="flex-grow bg-base-300 w-full mt-16 px-8 py-12"><ul>{result?.data?.transactions.map((transaction, txnIndex) =>transaction.swaps.map((swap, swapIndex) => (<li key={`${txnIndex}-${swapIndex}`}><div>Amount0: {swap?.amount0 ?? "N/A"}</div><div>Amount1: {swap?.amount1 ?? "N/A"}</div><div>USD Amount: {swap?.amountUSD ?? "N/A"}</div><div>Pool Token0: {swap?.pool.token0?.name ?? "Unknown"}</div><div>Pool Token1: {swap?.pool.token1?.name ?? "Unknown"}</div></li>)),)}</ul></div></div></>);
Documentation Links
Conclusion
In conclusion, optimizing queries to The Graph by detecting inactive browser tabs significantly enhances the efficiency and performance of dapps. By implementing real-time data fetching and limiting active queries to only when the browser tab is in use, developers can reduce unnecessary requests and ensure that users receive timely and relevant data updates without the need for manual refreshes. This approach not only conserves resources but also provides a smoother and more responsive user experience.
About The Graph
is the leading indexing and query protocol powering the decentralized internet. Since launching in 2018, it has empowered tens of thousands of developers to effortlessly build and leverage across countless blockchains, including Ethereum, Solana, Arbitrum, Optimism, Base, Polygon, Celo, Soneium, and Avalanche. With powerful tools like Substreams and Token API, The Graph delivers high-performance, real-time access to onchain data. From low-latency indexing to rapid token data, it serves as the premier solution for building composable, data drive dapps.
Discover more about how The Graph is shaping the future of decentralized physical infrastructure networks (DePIN) and stay connected with the community. Follow The Graph on , , , , , and . Join the community on The Graph’s , join technical discussions on The Graph’s .
oversees The Graph Network. , , , , and are seven of the many organizations within The Graph ecosystem.