# Read feeds offchain

> Read block-latency feeds using JS, Python, Rust, or Go.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

Source: https://dev.flare.network/ftso/guides/read-feeds-offchain

This guide provides code examples demonstrating how to read FTSOv2 feeds offchain using various programming languages. To read a block-latency feed offchain, you need three key pieces of information:

1.  **RPC Endpoint URL:** The RPC Endpoint URL determines which network your code will interact with. You can use a node provider service or point to your [own RPC node](/run-node#rpc-node). A comprehensive list of public and private RPC endpoints for all Flare networks is available on the [Network Configuration](/network/overview#configuration) page.
    
2.  **Contract Address:** Feeds are served on the `FtsoV2` contract, whose address varies by network. You can obtain this address in two ways:
    
    -   **From the Solidity Reference page:** Find the `FtsoV2` address for each network on the [Solidity Reference](/ftso/solidity-reference) page.
        
        **OR**
        
    -   **Query the FlareContractRegistry Contract:** The `FlareContractRegistry` contract has the same address across all networks. You can query it to get the `FtsoV2` contract address. Refer to the specific language guides for examples: - [JavaScript](/network/guides/flare-for-javascript-developers#make-query) - [Python](/network/guides/flare-for-python-developers#make-query) - [Rust](/network/guides/flare-for-rust-developers#make-query) - [Go](/network/guides/flare-for-go-developers#make-query)
        
3.  **Feed IDs:** The feeds you want to read are uniquely identified by their ID. A list of feed IDs is provided on the [Block-Latency Feeds](/ftso/feeds) page.
    

tip

All examples in this guide are available at [developer-hub/examples](https://github.com/flare-foundation/developer-hub/tree/main/examples).

This example uses [web3.js](https://github.com/web3/web3.js) and [Flare Periphery Contract Artifacts](https://www.npmjs.com/package/@flarenetwork/flare-periphery-contract-artifacts) to retrieve FTSOv2 feed data for FLR/USD, BTC/USD, and ETH/USD on Flare Testnet Coston2.

```
npm install web3npm install @flarenetwork/flare-periphery-contract-artifacts
```

ftsov2\_consumer.js

```
// THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.import { Web3 } from "web3";import { interfaceToAbi } from "@flarenetwork/flare-periphery-contract-artifacts";// FtsoV2 address (Flare Testnet Coston2)// See https://dev.flare.network/ftso/solidity-referenceconst FTSOV2_ADDRESS = "0x3d893C53D9e8056135C26C8c638B76C8b60Df726";const RPC_URL = "https://coston2-api.flare.network/ext/C/rpc";const FEED_IDS = [  "0x01464c522f55534400000000000000000000000000", // FLR/USD  "0x014254432f55534400000000000000000000000000", // BTC/USD  "0x014554482f55534400000000000000000000000000", // ETH/USD];// ABI for FtsoV2const abi = interfaceToAbi("FtsoV2Interface", "coston2");export async function main() {  // Connect to an RPC node  const w3 = new Web3(RPC_URL);  // Set up contract instance  const ftsov2 = new w3.eth.Contract(abi, FTSOV2_ADDRESS);  // Fetch current feeds  const res = await ftsov2.methods.getFeedsById(FEED_IDS).call();  // Log results  console.log("Feeds:", res["0"]);  console.log("Decimals:", res["1"]);  console.log("Timestamp:", res["2"]);  return res;}main();
```

This example uses [web3.js](https://github.com/web3/web3.js) and [Flare Periphery Contract Artifacts](https://www.npmjs.com/package/@flarenetwork/flare-periphery-contract-artifacts) to retrieve FTSOv2 feed data for FLR/USD, BTC/USD, and ETH/USD on Flare Testnet Coston2.

```
npm install ethersnpm install @flarenetwork/flare-periphery-contract-artifacts
```

ftsov2\_consumer.js

```
// THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.import { ethers } from "ethers";import { interfaceToAbi } from "@flarenetwork/flare-periphery-contract-artifacts";// FtsoV2 address (Flare Testnet Coston2)// See https://dev.flare.network/ftso/solidity-referenceconst FTSOV2_ADDRESS = "0x3d893C53D9e8056135C26C8c638B76C8b60Df726";const RPC_URL = "https://coston2-api.flare.network/ext/C/rpc";const FEED_IDS = [  "0x01464c522f55534400000000000000000000000000", // FLR/USD  "0x014254432f55534400000000000000000000000000", // BTC/USD  "0x014554482f55534400000000000000000000000000", // ETH/USD];// ABI for FtsoV2const abi = interfaceToAbi("FtsoV2Interface", "coston2");export async function main() {  // Connect to an RPC node  const provider = new ethers.JsonRpcProvider(RPC_URL);  // Set up contract instance  const ftsov2 = new ethers.Contract(FTSOV2_ADDRESS, abi, provider);  // Fetch current feeds  const res = await ftsov2.getFeedsById.staticCall(FEED_IDS);  // Log results  console.log("Feeds:", res[0]);  console.log("Decimals:", res[1]);  console.log("Timestamp:", res[2]);  return res;}main();
```

This example uses [web3.py](https://github.com/ethereum/web3.py) to retrieve FTSOv2 feed values for FLR/USD, BTC/USD, and ETH/USD on Flare Testnet Coston2.

```
uv add web3
```

```
pip install web3
```

ftsov2\_consumer.py

```
# THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.import asynciofrom web3 import AsyncHTTPProvider, AsyncWeb3# FtsoV2 address (Flare Testnet Coston2)# See https://dev.flare.network/ftso/solidity-referenceFTSOV2_ADDRESS = "0x3d893C53D9e8056135C26C8c638B76C8b60Df726"RPC_URL = "https://coston2-api.flare.network/ext/C/rpc"FEED_IDS = [    "0x01464c522f55534400000000000000000000000000",  # FLR/USD    "0x014254432f55534400000000000000000000000000",  # BTC/USD    "0x014554482f55534400000000000000000000000000",  # ETH/USD]# ABI for FtsoV2ABI = '[{"inputs":[{"internalType":"address","name":"_addressUpdater","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FTSO_PROTOCOL_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fastUpdater","outputs":[{"internalType":"contract IFastUpdater","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fastUpdatesConfiguration","outputs":[{"internalType":"contract IFastUpdatesConfiguration","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAddressUpdater","outputs":[{"internalType":"address","name":"_addressUpdater","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes21","name":"_feedId","type":"bytes21"}],"name":"getFeedById","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"int8","name":"","type":"int8"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes21","name":"_feedId","type":"bytes21"}],"name":"getFeedByIdInWei","outputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint64","name":"_timestamp","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getFeedByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"int8","name":"","type":"int8"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getFeedByIndexInWei","outputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint64","name":"_timestamp","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getFeedId","outputs":[{"internalType":"bytes21","name":"","type":"bytes21"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes21","name":"_feedId","type":"bytes21"}],"name":"getFeedIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes21[]","name":"_feedIds","type":"bytes21[]"}],"name":"getFeedsById","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"int8[]","name":"","type":"int8[]"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes21[]","name":"_feedIds","type":"bytes21[]"}],"name":"getFeedsByIdInWei","outputs":[{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"uint64","name":"_timestamp","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_indices","type":"uint256[]"}],"name":"getFeedsByIndex","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"int8[]","name":"","type":"int8[]"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_indices","type":"uint256[]"}],"name":"getFeedsByIndexInWei","outputs":[{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"uint64","name":"_timestamp","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"relay","outputs":[{"internalType":"contract IRelay","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_contractNameHashes","type":"bytes32[]"},{"internalType":"address[]","name":"_contractAddresses","type":"address[]"}],"name":"updateContractAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"components":[{"internalType":"uint32","name":"votingRoundId","type":"uint32"},{"internalType":"bytes21","name":"id","type":"bytes21"},{"internalType":"int32","name":"value","type":"int32"},{"internalType":"uint16","name":"turnoutBIPS","type":"uint16"},{"internalType":"int8","name":"decimals","type":"int8"}],"internalType":"struct FtsoV2Interface.FeedData","name":"body","type":"tuple"}],"internalType":"struct FtsoV2Interface.FeedDataWithProof","name":"_feedData","type":"tuple"}],"name":"verifyFeedData","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]'  # noqa: E501async def main() -> tuple[list, list, int]:    # Connect to an RPC node    w3 = AsyncWeb3(        AsyncHTTPProvider(RPC_URL),    )    # Set up contract instance    ftsov2 = w3.eth.contract(address=w3.to_checksum_address(FTSOV2_ADDRESS), abi=ABI)    # Fetch current feeds    feeds, decimals, timestamp = await ftsov2.functions.getFeedsById(FEED_IDS).call()    # Print results    print("Feeds:", feeds)    print("Decimals:", decimals)    print("Timestamp:", timestamp)    return feeds, decimals, timestampif __name__ == "__main__":    asyncio.run(main())
```

This example uses [alloy-rs](https://github.com/alloy-rs) to retrieve FTSOv2 feed data for FLR/USD, BTC/USD, and ETH/USD on Flare Testnet Coston2.

```
cargo add alloy eyre tokio --features alloy/full,tokio/rt,tokio/rt-multi-thread,tokio/macros
```

ftsov2\_consumer.rs

```
// THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.use alloy::{    primitives::{address, fixed_bytes},    providers::ProviderBuilder,    sol,};use eyre::Result;sol!(    #[sol(rpc)]    FtsoV2,    r#"[{"inputs":[{"internalType":"address","name":"_addressUpdater","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FTSO_PROTOCOL_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fastUpdater","outputs":[{"internalType":"contract IFastUpdater","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fastUpdatesConfiguration","outputs":[{"internalType":"contract IFastUpdatesConfiguration","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAddressUpdater","outputs":[{"internalType":"address","name":"_addressUpdater","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes21","name":"_feedId","type":"bytes21"}],"name":"getFeedById","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"int8","name":"","type":"int8"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes21","name":"_feedId","type":"bytes21"}],"name":"getFeedByIdInWei","outputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint64","name":"_timestamp","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getFeedByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"int8","name":"","type":"int8"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getFeedByIndexInWei","outputs":[{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint64","name":"_timestamp","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getFeedId","outputs":[{"internalType":"bytes21","name":"","type":"bytes21"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes21","name":"_feedId","type":"bytes21"}],"name":"getFeedIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes21[]","name":"_feedIds","type":"bytes21[]"}],"name":"getFeedsById","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"int8[]","name":"","type":"int8[]"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes21[]","name":"_feedIds","type":"bytes21[]"}],"name":"getFeedsByIdInWei","outputs":[{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"uint64","name":"_timestamp","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_indices","type":"uint256[]"}],"name":"getFeedsByIndex","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"int8[]","name":"","type":"int8[]"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_indices","type":"uint256[]"}],"name":"getFeedsByIndexInWei","outputs":[{"internalType":"uint256[]","name":"_values","type":"uint256[]"},{"internalType":"uint64","name":"_timestamp","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"relay","outputs":[{"internalType":"contract IRelay","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_contractNameHashes","type":"bytes32[]"},{"internalType":"address[]","name":"_contractAddresses","type":"address[]"}],"name":"updateContractAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"components":[{"internalType":"uint32","name":"votingRoundId","type":"uint32"},{"internalType":"bytes21","name":"id","type":"bytes21"},{"internalType":"int32","name":"value","type":"int32"},{"internalType":"uint16","name":"turnoutBIPS","type":"uint16"},{"internalType":"int8","name":"decimals","type":"int8"}],"internalType":"struct FtsoV2Interface.FeedData","name":"body","type":"tuple"}],"internalType":"struct FtsoV2Interface.FeedDataWithProof","name":"_feedData","type":"tuple"}],"name":"verifyFeedData","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]"#);#[tokio::main]async fn main() -> Result<()> {    // FtsoV2 address (Flare Testnet Coston2)    // See https://dev.flare.network/ftso/solidity-reference    let ftso_address = address!("C4e9c78EA53db782E28f28Fdf80BaF59336B304d");    let rpc_url = "https://coston2-api.flare.network/ext/C/rpc".parse()?;    let feed_ids = vec![        fixed_bytes!("01464c522f55534400000000000000000000000000"), // FLR/USD        fixed_bytes!("014254432f55534400000000000000000000000000"), // BTC/USD        fixed_bytes!("014554482f55534400000000000000000000000000"), // ETH/USD    ];    // Connect to an RPC node    let provider = ProviderBuilder::new().connect_http(rpc_url);    // Set up contract instance    let ftsov2 = FtsoV2::new(ftso_address, provider);    // Fetch current feeds    let FtsoV2::getFeedsByIdReturn { _0, _1, _2 } = ftsov2.getFeedsById(feed_ids).call().await?;    // Print results    println!("Feeds:{_0:?}");    println!("Decimals:{_1:?}");    println!("Timestamp:{_2:?}");    Ok(())}
```

This example uses the Go API from [Geth](https://geth.ethereum.org) to retrieve FTSOv2 feed data for FLR/USD, BTC/USD, and ETH/USD from Flare Testnet Coston2.

```
go get github.com/ethereum/go-ethereum/ethclient
```

With Go, you need to manually fetch the contract's ABI and generate the Go bindings.

Copy the [FtsoV2 ABI](/ftso/solidity-reference) and paste it into a file named `FtsoV2.abi`, located in the root of your project, i.e. same level as `go.mod`. Then using [abigen](https://geth.ethereum.org/docs/tools/abigen), generate the Go bindings.

```
abigen --abi FtsoV2.abi --pkg main --type FtsoV2 --out FtsoV2.go
```

ftsov2\_consumer.go

```
// THIS IS EXAMPLE CODE. DO NOT USE THIS CODE IN PRODUCTION.package mainimport (	"context"	"encoding/hex"	"fmt"	"github.com/ethereum/go-ethereum/accounts/abi/bind"	"github.com/ethereum/go-ethereum/common"	"github.com/ethereum/go-ethereum/ethclient")func FtsoV2Consumer() {	// FtsoV2 address (Flare Testnet Coston2)	// See https://dev.flare.network/ftso/solidity-reference	ftsoV2Address := common.HexToAddress("0x3d893C53D9e8056135C26C8c638B76C8b60Df726")	rpcUrl := "https://coston2-api.flare.network/ext/C/rpc"	// Connect to an RPC node	client, _ := ethclient.Dial(rpcUrl)	// Set up contract instance	ftsov2, _ := NewFtsoV2(ftsoV2Address, client)	feedIds := []string{		"0x01464c522f55534400000000000000000000000000", // FLR/USD		"0x014254432f55534400000000000000000000000000", // BTC/USD		"0x014554482f55534400000000000000000000000000", // ETH/USD	}	// Convert feedIds from string to bytes	var feedIdsBytes [][21]byte	for _, feedHex := range feedIds {		bytes, _ := hex.DecodeString(feedHex[2:])		feedBytes := [21]byte{}		copy(feedBytes[:], bytes)		feedIdsBytes = append(feedIdsBytes, feedBytes)	}	// Fetch current feeds	var res []interface{}	opts := &bind.CallOpts{Context: context.Background()}	ftsov2.FtsoV2Caller.contract.Call(opts, &res, "getFeedsById", feedIdsBytes)	// Print results	fmt.Println(res)	fmt.Println("Feeds:", res[0])	fmt.Println("Decimals:", res[1])	fmt.Println("Timestamp:", res[2])}
```
