Skip to content

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,
})

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

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

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:

/*
* If you don't want the Algorand client to cache the signer,
* you can manually provide the signer.
*/
await algorand.send.payment({
sender: randomAccountA,
receiver: randomAccountB,
amount: AlgoAmount.Algo(1),
signer: randomAccountA.signer, // The signer must be manually provided
})

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

/*
* By setting signers of accounts to the algorand client, the client will cache the signers
* and use them to sign transactions when the sender is one of the accounts.
*/
// 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),
})

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:

  • Fee: The transaction fee (in microAlgos)
  • First Valid Round: The first blockchain round where the transaction can be processed
  • Last Valid Round: The last blockchain round where the transaction can be processed (after this, the transaction expires)
  • Genesis ID: The identifier for the Algorand network (e.g., “mainnet-v1.0”)
  • Genesis Hash: The hash of the genesis block for the network
  • Min Fee: The minimum fee required by the network

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:

  • Increases latency: Each transaction would require an additional network request
  • Increases network load: Both for your application and the Algorand node
  • Slows down user experience: Especially when creating multi-transaction groups

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:

  • algorand.setDefaultValidityWindow(validityWindow) - Set the default validity window (number of rounds from the current known round that the transaction will be valid to be accepted for), having a smallish value for this is usually ideal to avoid transactions that are valid for a long future period and may be submitted even after you think it failed to submit if waiting for a particular number of rounds for the transaction to be successfully submitted. The validity window defaults to 10, except in automated testing where it’s set to 1000 when targeting LocalNet.
  • algorand.setSuggestedParams(suggestedParams, until?) - Set the suggested network parameters to use (optionally until the given time)
  • algorand.setSuggestedParamsTimeout(timeout) - Set the timeout that is used to cache the suggested network parameters (by default 3 seconds)
  • algorand.getSuggestedParams() - Get the current suggested network parameters object, either the cached value, or if the cache has expired a fresh value
/*
* 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)

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:

  • Type-safe method calls
  • Automatic parameter validation
  • IntelliSense code completion support

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:

  • Directoryhello_world
    • hello_world_client.py
    • HelloWorld.approval.puya.map
    • HelloWorld.approval.teal
    • HelloWorld.arc56.json
    • HelloWorld.clear.puya.map
    • HelloWorld.clear.puya.teal

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
*/
//For single app client instance
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 })
/*
Get typed app client by creator and name
*/
// For single app client instance
let appClientByCreator = await algorand.client.getTypedAppClientByCreatorAndName(HelloWorldClient, {
creatorAddress: randomAccountA.addr,
appName: 'contract-name',
// ...
})
// or
appClientByCreator = await HelloWorldClient.fromCreatorAndName({
algorand,
creatorAddress: randomAccountA.addr,
appName: 'contract-name',
// ...
})
// For multiple app client instances use the factory
let appClientFactory = algorand.client.getTypedAppFactory(HelloWorldFactory)
// or
appClientFactory = new HelloWorldFactory({ algorand })
const appClientByCreator1 = await appClientFactory.getAppClientByCreatorAndName({
creatorAddress: randomAccountA.addr,
appName: 'contract-name',
// ...
})
const appClientByCreator2 = await appClientFactory.getAppClientByCreatorAndName({
creatorAddress: randomAccountA.addr,
appName: 'contract-name-2',
// ...
})

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)
// or
createFactory = new HelloWorldFactory({ algorand })
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',
})

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)

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
// In this case the generated factory is called `HelloWorldAppFactory` and is accessible via AppClients
// These require environment variables to be present, or it will retrieve from default LocalNet
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,
// you can use .deploy() to deploy idempotently if the app wasn't previously
// deployed or needs to be updated if that's allowed)
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)

When to Use Each Client Type

  • Use the AlgorandClient when you need to:

    • Send basic transactions (payments, asset transfers)
    • Work with blockchain data in a general way
    • Interact with contracts you don’t have specifications for
  • Use Typed App Clients when you need to:

    • Deploy and interact with specific smart contracts
    • Benefit from type safety and IntelliSense
    • Build applications that leverage contract-specific functionality

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:

  • Start with the AlgorandClient for general blockchain interactions
  • Generate Typed Application Clients for your smart contracts
  • Leverage the stateful design of these clients to simplify your code