AlgoKit Clients | Algorand Developer Portal

AlgoKit Clients

When building on Algorand, you need reliable ways to communicate with the blockchain—sending transactions, interacting with smart contracts, and accessing blockchain data. AlgoKit Utils clients provide straightforward, developer-friendly interfaces for these interactions, reducing the complexity typically associated with blockchain development. This guide explains how to use these clients to simplify common Algorand development tasks, whether you’re sending a basic transaction or deploying complex smart contracts.

AlgoKit offers two main types of clients to interact with the Algorand blockchain:

  1. Algorand Client - A general-purpose client for all Algorand interactions, including:
    • Crafting, grouping, and sending transactions through a fluent interface of chained methods
    • Accessing network services through REST API clients for algod, indexer, and kmd
    • Configuring connection and transaction parameters with sensible defaults and optional overrides
  2. Typed Application Client - A specialized, auto-generated client for interacting with specific smart contracts:
    • Provides type-safe interfaces generated from ARC-56 or ARC-32 contract specification files
    • Enables IntelliSense-driven development experience that includes the smart contract methods
    • Reduces errors through real-time type checking of arguments provided to smart contract methods

Let’s explore each client type in detail.

Algorand Client: Gateway to the Blockchain

The AlgorandClient serves as your primary entry point for all Algorand operations. Think of it as your Swiss Army knife for blockchain interactions.

Getting Started with AlgorandClient

You can create an AlgorandClient instance in several ways, depending on your needs:

// Point to the network configured through environment variables or
//  if no environment variables it will point to the default LocalNet
//  configuration

const client1 = AlgorandClient.fromEnvironment()

// Point to default LocalNet configuration
const client2 = AlgorandClient.defaultLocalNet()

// Point to TestNet using AlgoNode free tier
const client3 = AlgorandClient.testNet()

// Point to MainNet using AlgoNode free tier
const client4 = AlgorandClient.mainNet()

// Point to a pre-created algod client
const client5 = AlgorandClient.fromClients({ algod })

// Point to pre-created algod, indexer and kmd clients
const client6 = AlgorandClient.fromClients({ algod, indexer, kmd })

// Point to custom configuration for algod
const client7 = AlgorandClient.fromConfig({
  algodConfig: {
    server: 'http://localhost',
    port: '4001',
    token: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
  },
})

// Point to custom configuration for algod, indexer and kmd
const client8 = AlgorandClient.fromConfig({
  algodConfig: algodConfig,
  indexerConfig: indexerConfig,
  kmdConfig: kmdConfig,
})

Source

# Point to the network configured through environment variables or
#  if no environment variables it will point to the default LocalNet
#  configuration

algorand_client = AlgorandClient.from_environment()

# Point to default LocalNet configuration
algorand_client = AlgorandClient.default_localnet()

# Point to TestNet using AlgoNode free tier
algorand_client = AlgorandClient.testnet()

# Point to MainNet using AlgoNode free tier
algorand_client = AlgorandClient.mainnet()

# Point to a pre-created algod client
algorand_client = AlgorandClient.from_clients(algod)

# Point to pre-created algod, indexer and kmd clients
algorand_client = AlgorandClient.from_clients(algod, indexer, kmd)

# Point to custom configuration for algod
algorand_client = AlgorandClient.from_config(
    AlgoClientNetworkConfig(
        server="http://localhost",
        token="4001",
    )
)

# Point to custom configuration for algod, indexer and kmd
algorand_client = AlgorandClient.from_config(
    algod_config, indexer_config, kmd_config
)

Source

These factory methods make it easy to connect to different Algorand networks without manually configuring connection details.

Once you have an AlgorandClient instance, you can access the REST API clients for the various Algorand APIs via the AlgorandClient.client property:

const algorandClient = AlgorandClient.fromEnvironment()

const algodClient = algorandClient.client.algod

const indexerClient = algorandClient.client.indexer

const kmdClient = algorandClient.client.kmd

Source

algod = algorand_client.client.algod

indexer = algorand_client.client.indexer

kmd = algorand_client.client.kmd

Source

For more information about the functionalities of the REST API clients, refer to the following pages:

algod API Reference Interact with Algorand nodes, submit transactions, and get blockchain status

Indexer API Reference Query historical transactions, account information, and blockchain data

kmd API Reference Manage wallets and keys (primarily for development environments)

Understanding AlgorandClient’s Stateful Design

The AlgorandClient is “stateful”, meaning that it caches various information that are reused multiple times. This allows the AlgorandClient to avoid redundant requests to the blockchain and to provide a more efficient interface for interacting with the blockchain. This is an important concept to understand before using the AlgorandClient.

Account Signer Caching

When sending transactions, you need to sign them with a private key. AlgorandClient can cache these signing capabilities, eliminating the need to provide signing information for every transaction, as you can see in the following example:

await algorand.send.payment({
  sender: randomAccountA,
  receiver: randomAccountB,
  amount: AlgoAmount.Algo(1),
  signer: randomAccountA.signer, // The signer must be manually provided
})

Source

algorand_client.send.payment(
    PaymentParams(
        sender=account_a.address,
        receiver=account_b.address,
        amount=AlgoAmount(algo=1),
        signer=account_a.signer,  # The signer must be manually provided
    )
)

Source

The same example, but with different approaches to signer caching demonstrated:

// If no signer is provided, the client will use the default signer
algorand.setDefaultSigner(randomAccountA.signer)

// If you have an address and a signer, use this method to set the signer
algorand.setSigner(randomAccountA.addr, randomAccountA.signer)

// If you have a `SigningAccount` object, use this method to set the signer
algorand.setSignerFromAccount(randomAccountA)

// The Algorand client can directly send this payment transaction without needing a signer because it is tracking the signer for account_a.
await algorand.send.payment({
  sender: randomAccountA,
  receiver: randomAccountB,
  amount: AlgoAmount.Algo(1),
})

Source

algorand_client.set_default_signer(account_a.signer)

algorand_client.set_signer(account_a.address, account_a.signer)

algorand_client.set_signer_from_account(account_a)

# The Algorand client can directly send this payment transaction without needing a signer because it is tracking the signer for account_a.
algorand_client.send.payment(
    PaymentParams(
        sender=account_a.address,
        receiver=account_b.address,
        amount=AlgoAmount(algo=1),
    )
)

Source

This caching mechanism simplifies your code, especially when sending multiple transactions from the same account.

Suggested Parameter Caching

AlgorandClient caches network provided transaction values (suggested parameters) for you automatically to reduce network traffic. It has a set of default configurations that control this behavior, but you have the ability to override and change the configuration of this behavior.

What Are Suggested Parameters?

In Algorand, every transaction requires a set of network-specific parameters that define how the transaction should be processed. These “suggested parameters” include:

These parameters are called “suggested” because the network provides recommended values, but developers can modify them (for example, to increase the fee during network congestion).

Why Cache These Parameters?

Without caching, your application would need to request these parameters from the network before every transaction, which:

Since these parameters only change every few seconds (when new blocks are created), repeatedly requesting them wastes resources.

How Parameter Caching Works

The AlgorandClient automatically:

  1. Requests suggested parameters when needed
  2. Caches them for a configurable time period (default: 3 seconds)
  3. Reuses the cached values for subsequent transactions
  4. Refreshes the cache when it expires
Customized Parameter Caching

AlgorandClient has a set of default configurations that control this behavior, but you have the ability to override and change the configuration of this behavior:

// Sets the default validity window for transactions.
// @param validityWindow The number of rounds between the first and last valid rounds
// @returns The `algorand` so method calls can be chained
algorand.setDefaultValidityWindow(1000)

// Get suggested params for a transaction (either cached or from algod if the cache is stale or empty)
const sp = await algorand.getSuggestedParams()
// The suggested params can be modified like below
sp.flatFee = true
sp.fee = 2000

// Sets a cache value to use for suggested params. Use this method to use modified suggested params for the next transaction.
// @param suggestedParams The suggested params to use
// @param until A timestamp until which to cache, or if not specified then the timeout is used
// @returns The `algorand` so method calls can be chained
algorand.setSuggestedParamsCache(sp)

// Sets the timeout for caching suggested params. If set to 0, the Algorand client will request suggested params from the algod client every time.
// @param timeout The timeout in milliseconds
// @returns The `algorand` so method calls can be chained
algorand.setSuggestedParamsCacheTimeout(0)

Source

# Sets the default validity window for transactions.
#:param validity_window: The number of rounds between the first and last valid rounds
#:return: The `AlgorandClient` so method calls can be chained
algorand_client.set_default_validity_window(1000)

# Get suggested params for a transaction (either cached or from algod if the cache is stale or empty)
sp = algorand_client.get_suggested_params()
# The suggested params can be modified like below
sp.flat_fee = True
sp.fee = 2000

# Sets a cache value to use for suggested params. Use this method to use modified suggested params for the next transaction.
#:param suggested_params: The suggested params to use
#:param until: A timestamp until which to cache, or if not specified then the timeout is used
#:return: The `AlgorandClient` so method calls can be chained
algorand_client.set_suggested_params_cache(sp)

# Sets the timeout for caching suggested params. If set to 0, the Algorand client will request suggested params from the algod client every time.
#:param timeout: The timeout in milliseconds
#:return: The `AlgorandClient` so method calls can be chained
algorand_client.set_suggested_params_cache_timeout(0)

Source

By understanding and properly configuring suggested parameter caching, you can optimize your application’s performance while ensuring transactions are processed correctly by the Algorand network.

Typed App Clients: Smart Contract Interaction Simplified

While the AlgorandClient handles general blockchain interactions, typed app clients provide specialized interfaces for deployed applications. These clients are generated from contract specifications (ARC-56/ ARC-32) and offer:

Generating App Clients

The relevant smart contract’s app client is generated using the ARC56/ARC32 ABI file. There are two different ways to generate an application client for a smart contract:

1. Using the AlgoKit Build CLI Command

When you are using the AlgoKit smart contract template for your project, compiling your ARC4 smart contract written in either TypeScript or Python will automatically generate the TypeScript or Python application client for you depending on what language you chose for contract interaction. Simply run the following command to generate the artifacts including the typed application client:

algokit project run build

After running the command, you should see the following artifacts generated in the artifacts directory under the smart_contracts directory:

2. Using the AlgoKit Generate CLI Command

There is also an AlgoKit CLI command to generate the app client for a smart contract. You can also use it to define custom commands inside of the .algokit.toml file in your project directory. Note that you can specify what language you want for the application clients with the file extensions .ts for TypeScript and .py for Python.

# To output a single arc32.json to a TypeScript typed app client:
algokit generate client path/to/arc32.json --output client.ts

# To process multiple arc32.json in a directory structure and output to a TypeScript app client for each in the current directory:
algokit generate client smart_contracts/artifacts --output {contract_name}.ts

# To process multiple arc32.json in a directory structure and output to a Python client alongside each arc32.json:
algokit generate client smart_contracts/artifacts --output {app_spec_path}/client.py

When compiled, all ARC-4 smart contracts generate an arc56.json or arc32.json file depending on what app spec was used. This file contains the smart contract’s extended ABI, which follows the ARC-32 standard.

Working with a Typed App Client Object

To get an instance of a typed client you can use an AlgorandClient instance or a typed app Factory instance.

The approach to obtaining a client instance depends on how many app clients you require for a given app spec and if the app has already been deployed, which is summarised below:

App is Already Deployed

//Get typed app client by id

let appClient = await algorand.client.getTypedAppClientById(HelloWorldClient, {
  appId: 1234n,
})

// or
appClient = new HelloWorldClient({
  algorand,
  appId: 1234n,
})

// For multiple app client instances use the factory
const factory = algorand.client.getTypedAppFactory(HelloWorldFactory)
// or
const factory2 = new HelloWorldFactory({ algorand })
const appClient1 = await factory.getAppClientById({ appId: 1234n })
const appClient2 = await factory.getAppClientById({ appId: 4321n })
from smart_contracts.artifacts.hello_world.hello_world_client import (
    HelloArgs,
    HelloWorldClient,
    HelloWorldFactory,
)

# Get a single typed app client by id
app_client = algorand_client.client.get_typed_app_client_by_id(
    HelloWorldClient,
    app_id=1234,
)

# or
app_client = HelloWorldClient(
    algorand=algorand_client,
    app_id=1234,
)

# For multiple app client instances use the factory
factory = algorand_client.client.get_typed_app_factory(HelloWorldFactory)
# or
factory = HelloWorldFactory(algorand_client)
app_client1 = factory.get_app_client_by_id(app_id=1234)
app_client2 = factory.get_app_client_by_id(app_id=4321)

App is not Deployed

For applications that need to work with multiple instances of the same smart contract spec, factories provide a convenient way to manage multiple clients:

// Deploy a New App
let createFactory = algorand.client.getTypedAppFactory(HelloWorldFactory)
const { result, appClient: newAppClient } = await createFactory.send.create.bare()

// or if the contract has a custom create method:
const customFactory = algorand.client.getTypedAppFactory(CustomCreateFactory)
const { result: customCreateResult, appClient: customCreateAppClient } = await customFactory.send.create.customCreate({ args: { age: 28 } })

// Deploy or Resolve App Idempotently by Creator and Name
const { result: deployResult, appClient: deployedClient } = await createFactory.deploy({
  appName: 'contract-name',
})
from smart_contracts.artifacts.custom_create.custom_create_client import (
    CustomCreateArgs,
    CustomCreateFactory,
)

# Deploy a New App
factory = algorand_client.client.get_typed_app_factory(HelloWorldFactory)
app_client, create_response = factory.send.create.bare()

# or if the contract has a custom create method:
factory2 = algorand_client.client.get_typed_app_factory(CustomCreateFactory)
custom_create_app_client, factory_create_response = factory2.send.create.custom_create(CustomCreateArgs(age=28))

# Deploy or Resolve App Idempotently by Creator and Name
app_client, deploy_response = factory.deploy(app_name="contract-name",)

Calling a Smart Contract Method

To call a smart contract method using the application client instance, follow these steps:

const methodResponse = await appClient.send.sayHello({ args: { firstName: 'there', lastName: 'world' } })
console.log(methodResponse.return)
response = app_client.send.hello(args=HelloArgs(name="world"))
print(response.abi_return)

The typed app client ensures you provide the correct parameters and handles all the underlying transaction construction and submission.

Example: Deploying and Interacting with a Smart Contract

For a simple example that deploys a contract and calls a hello method, see below:

// A similar working example can be seen in the AlgoKit init production smart contract templates
const algorand = AlgorandClient.fromEnvironment()
const deployer = await algorand.account.fromEnvironment('DEPLOYER', (1).algo())

// Create the typed app factory
const factory = algorand.client.getTypedAppFactory(HelloWorldFactory, {
  defaultSender: deployer.addr,
})

// Create the app and get a typed app client for the created app (note: this creates a new instance of the app every time,
const { appClient } = await factory.send.create.bare()

// Make a call to an ABI method and print the result
const response = await appClient.send.sayHello({ args: { firstName: 'there', lastName: 'world' } })
console.log(response.return)
from algokit_utils import AlgorandClient
from smart_contracts.artifacts.hello_world.hello_world_client import (
    HelloArgs,
    HelloWorldClient,
    HelloWorldFactory,
)

# These require environment variables to be present, or it will retrieve from default LocalNet
algorand = AlgorandClient.from_environment()

delepi.deployer = algorand.account.from_environment("DEPLOYER", AlgoAmount.from_algo(1))

# Create the typed app factory
factory = algorand.client.get_typed_app_factory(HelloWorldFactory, default_sender=deployer.address)

# Create the app and get a typed app client for the created app
app_client, create_response = factory.send.create.bare()

# Make a call to an ABI method and print the result
response = app_client.send.hello(args=HelloArgs(name="world"))
print(response.abi_return)

When to Use Each Client Type

For most Algorand applications, you’ll likely use both: AlgorandClient for general blockchain operations and Typed App Clients for smart contract interactions.

Next Steps

Now that you understand AlgoKit Utils Clients, you’re ready to start building on Algorand with confidence. Remember: