Rate limiting
Qlik Cloud platform features and APIs rely on rate limits to help provide a predictably pleasant experience for users.
The details of how and when rate limiting works differs between features. This page gives an overview of the rate limits you’re likely to encounter for Qlik Cloud platform features, and then notes how the limits apply to each feature.
Overview
In general, rate limits for published APIs (documented on qlik.dev) are evaluated on a per tier, per user, per tenant basis.
Endpoints not published on qlik.dev are considered private. However, they may share tiers with published endpoints.
Tier | Limit | Description |
---|---|---|
Tier 1 | 1,000 per min | This tier contains the majority of GET requests. The limit is evaluated over a 5-minute window to support bursts of requests. |
Tier 2 | 100 per min | This tier applies to endpoints intended to create, update, and delete resources. The limit is evaluated over a 5-minute window to support bursts of requests. |
Special | Varies | The rate limit for Special endpoints is published in the relevant API specification. |
API rate limiting
Your app’s requests to Qlik Cloud REST APIs are evaluated per tier, per user, per tenant. Rate limit windows are per minute unless documented otherwise.
All Qlik Cloud plans receive the same rate limit configuration. It’s not possible to customize this on a per-customer or per-tenant basis.
The Facts
section of each endpoint’s reference documentation will indicate its
rate limit tier. For an example of a Special endpoint, see the Reloads API documentation.
Some endpoints may have additional rate limits for error responses.
Each tier’s limits are subject to change.
Tenant rate limit
In addition to the per-user rate limit, there is a tenant rate limit which determines how many users may send requests at the same time. This is determined by:
tenantRateLimit = (user rate limit) * (number of users in the tenant) * 0.5
As an example, for a tenant with 100 users, users may in aggregate
send 1,000 * 100 * 0.5 = 50,000
requests within the rate limit window.
Rate limit handling with toolkits
Rate limit handling is built into the following toolkits:
- qlik-cli
- The Qlik Cloud Services and Qlik Platform Operations connectors in Qlik Application Automation
Responding to rate limiting conditions
If you exceed a rate limit when using any of Qlik Cloud’s published HTTP-based APIs,
you will receive an HTTP 429 Too Many Requests
error response, and a
Retry-After
HTTP header containing the number of seconds until you can retry.
< HTTP/1.1 429
< content-type: application/json
< content-length: 123
< retry-after: 13
{
"errors": [{
"code": "HTTP-429",
"title": "API rate limit reached.",
"detail": "You need to wait 13 seconds until limit is lifted."
}]
}
This response instructs your solution to wait 13 seconds before attempting another call. Calls to endpoints in the same tier are all blocked in the waiting period. Calls to endpoints in other tiers are not restricted.
For more information about the Retry-After
HTTP header, consult the
retry-after
header value for when you can make requests again.
Handling rate limits in your application
When integrating with Qlik APIs, it’s important to implement proper error handling for rate limits.
You should handle HTTP 429 Too Many Requests
error responses by pausing your requests and retrying after the specified
time.
Note: Rate limit handling is automatically managed in
qlik-cli
and the Platform Operations connector.
The following code snippets are examples of handling HTTP 429 Too Many Requests
error responses. These all use the
same logic:
- A function makes an API call.
- If the response is
HTTP 429 Too Many Requests
, requests are paused during the number of seconds specified in theretry-after
HTTP header. - Then, the function retries requests for 5 times maximum.
@qlik/api
The following code example shows you how to handle HTTP 429 Too Many Requests
error responses using @qlik/api
.
In this example, the spaces that the current user has access to are retrieved.
@qlik/api code example
import { auth, spaces } from '@qlik/api';
// Configuration for authentication
const hostConfig = {
authType: 'apikey',
host: 'https://<TENANT_HOSTNAME>.<REGION>.qlikcloud.com', // Replace with values for your Qlik Cloud tenant
apiKey: '<API_KEY>', // Replace with your API key
};
// Set the default host configuration for all API requests
auth.setDefaultHostConfig(hostConfig);
async function getSpacesWithRetry(maxRetries = 5) {
// Retry logic for handling rate limits
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`Attempting to retrieve spaces (attempt ${attempt})`);
// Get spaces using the high-level spaces.getSpaces function
const { status, headers, data: mySpaces } = await spaces.getSpaces();
// Check if HTTP 429 Too Many Requests error occurs
if (status === 429) {
if (attempt === maxRetries) {
throw new Error(`Max retries reached after ${attempt} attempts due to rate limiting`);
}
// Get the number of seconds included in the retry-after header
const retryAfter = headers['retry-after'];
const waitTime = retryAfter ? parseInt(retryAfter, 10) * 1000 : 1000; // Default to 1 second if no retry-after header
console.log(`Rate limit hit. Waiting ${waitTime / 1000} seconds before retrying.`);
// Wait for the retry-after time before retrying
await new Promise(resolve => setTimeout(resolve, waitTime));
} else if (status < 300) {
// Successful response, return spaces
return mySpaces;
} else {
throw new Error(`Request failed with status: ${status}`);
}
} catch (error) {
if (attempt === maxRetries) throw error; // Throw error if max retries are reached
console.error(`Error occurred: ${error.message}. Retrying request (attempt ${attempt})...`);
}
}
}
// Example usage
async function fetchData() {
try {
const mySpaces = await getSpacesWithRetry();
console.log('Spaces retrieved:', mySpaces);
} catch (error) {
console.error('Failed to retrieve spaces:', error.message);
}
}
fetchData();
Node.js
The following code example shows you how to handle HTTP 429 Too Many Requests
error responses in Node.js.
Node.js code example
import fetch from 'node-fetch';
// Fetch with retry logic for handling rate limits.
async function fetchWithRetry(url, options = {}, maxRetries = 5) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`Attempting request to ${url} (attempt ${attempt})`);
const response = await fetch(url, options);
// Check if HTTP 429 Too Many Requests error occurs
if (response.status === 429) {
if (attempt === maxRetries) {
throw new Error(`Max retries reached after ${attempt} attempts due to rate limiting.`);
}
// Get the number of seconds included in the retry-after header
const retryAfter = response.headers.get('retry-after');
const waitTime = retryAfter ? parseInt(retryAfter, 10) * 1000 : 1000; // Default to 1 second if no retry-after header
console.log(`Rate limit hit. Waiting ${waitTime / 1000} seconds before retrying.`);
// Wait for the retry-after time before retrying
await new Promise(resolve => setTimeout(resolve, waitTime));
} else if (response.ok) {
return await response.json(); // Return successful response
} else {
throw new Error(`Request failed with status: ${response.status}`);
}
} catch (error) {
if (attempt === maxRetries) throw error; // Throw error if the max number of retries is reached
console.error(`Error occurred: ${error.message}. Retrying request (attempt ${attempt})...`);
}
}
}
// Example usage
async function fetchData() {
const url = 'https://<TENANT_HOSTNAME>.<REGION>.qlikcloud.com/api/v1/<RESOURCE>'; // Replace with the API endpoint URL
const options = { method: 'GET', headers: { 'Authorization': 'Bearer <YOUR_ACCESS_TOKEN>' } }; // Replace with your access token
try {
const data = await fetchWithRetry(url, options);
console.log('Data retrieved:', data);
} catch (error) {
console.error('Failed to retrieve data:', error.message);
}
}
fetchData();
PowerShell
The following code example shows you how to handle HTTP 429 Too Many Requests
error responses in PowerShell.
PowerShell code example
# Fetch with retry logic for handling rate limits.
function Invoke-FetchWithRetry {
param (
[string]$Url, # The API endpoint URL
[string]$Method = 'GET', # HTTP method (default: GET)
[hashtable]$Headers = @{}, # Headers for the request
[object]$Body = $null, # Request body (optional)
[int]$MaxRetries = 5 # Maximum number of retries
)
$attempt = 1 # Track the retry attempt
while ($attempt -le $MaxRetries) {
try {
Write-Host "Attempting request to $Url (attempt $attempt)"
# Make the HTTP request
$response = Invoke-RestMethod -Uri $Url -Method $Method -Headers $Headers -Body $Body -ErrorAction Stop -PreserveAuthorizationOnRedirect
return $response # Return successful response
} catch {
$errorResponse = $_.Exception.Response
# Check if HTTP 429 Too Many Requests error occurs
if ($errorResponse.StatusCode -eq 429) {
if ($attempt -eq $MaxRetries) {
throw "Max retries reached after $attempt attempts due to rate limiting."
} # Throw error if the max number of retries is reached
# Get the number of seconds included in the retry-after header
$retryAfter = $errorResponse.Headers['retry-after']
$waitTime = if ($retryAfter) { [int]$retryAfter } else { 1 } # Default to 1 second if no retry-after header
Write-Host "Rate limit hit. Waiting $waitTime seconds before retrying."
# Wait for the specified time before retrying
Start-Sleep -Seconds $waitTime
} else {
Write-Host "Error occurred: $_. Retrying request (attempt {$attempt})..."
throw $_
}
}
$attempt++
}
}
# Example usage
$Url = "https://<TENANT_HOSTNAME>.<REGION>.qlikcloud.com/api/v1/<RESOURCE>" # Replace with the API endpoint URL
$Headers = @{
"Authorization" = "Bearer <YOUR_ACCESS_TOKEN>" # Replace with your access token
}
try {
$data = Invoke-FetchWithRetry -Url $Url -Method 'GET' -Headers $Headers
Write-Host "Data retrieved successfully:" $data
} catch {
Write-Host "Failed to retrieve data: $_"
}
Python
The following code example shows you how to handle HTTP 429 Too Many Requests
error responses in Python.
Python code example
import requests
import time
def fetch_with_retry(url, method='GET', headers=None, data=None, max_retries=5):
# Fetch with retry logic for handling rate limits.
for attempt in range(1, max_retries + 1):
try:
print(f"Attempting request to {url} (attempt {attempt})")
response = requests.request(method, url, headers=headers, json=data)
# Check if HTTP 429 Too Many Requests error occurs
if response.status_code == 429:
if attempt == max_retries:
raise Exception(f'Max retries reached after {attempt} attempts due to rate limiting.')
# Get the number of seconds included in the retry-after header
retry_after = response.headers.get('retry-after')
wait_time = int(retry_after) if retry_after else 1 # Default to 1 second if no retry-after header
print(f"Rate limit hit. Waiting {wait_time} seconds before retrying.")
# Wait for the specified time before retrying
time.sleep(wait_time)
elif response.ok:
return response.json() # Return successful response
else:
response.raise_for_status()
except requests.RequestException as e:
if attempt == max_retries:
raise e # Throw error if the max number of retries is reached
print(f"Error occurred: {e}. Retrying request (attempt {attempt})...")
# Example usage
def fetch_data():
url = 'https://<TENANT_HOSTNAME>.<REGION>.qlikcloud.com/api/v1/<RESOURCE>' # Replace with the API endpoint URL
headers = { 'Authorization': 'Bearer <YOUR_ACCESS_TOKEN>' } # Replace with your access token
try:
data = fetch_with_retry(url, headers=headers)
print("Data retrieved:", data)
except Exception as e:
print(f"Failed to retrieve data: {e}")
fetch_data()