Multi-cluster management is deprecated and will be sunset.
If you have issues with your Algolia infrastructure due to large volumes of data,
contact the Algolia support team.
Splitting data across multiple clusters
Assigning user data to a cluster
Without MCM, an application is bound to a single cluster. It means that splitting data across several clusters requires you to assign data to a specific application ID, so you can manually maintain and orchestrate the distribution by yourself. With MCM, all clusters use the same application ID. MCM keeps a mapping on each cluster to route requests to the correct cluster. All you need to do is assign a cluster to a user with theassignUserId method.
var response = await client.AssignUserIdAsync(
"user42",
new AssignUserIdParams { Cluster = "d4242-eu" }
);
final response = await client.assignUserId(
xAlgoliaUserID: "user42",
assignUserIdParams: AssignUserIdParams(cluster: "d4242-eu"),
);
response, err := client.AssignUserId(client.NewApiAssignUserIdRequest(
"user42",
search.NewEmptyAssignUserIdParams().SetCluster("d4242-eu")))
if err != nil {
// handle the eventual error
panic(err)
}
client.assignUserId("user42", new AssignUserIdParams().setCluster("d4242-eu"));
const response = await client.assignUserId({
xAlgoliaUserID: "user42",
assignUserIdParams: { cluster: "d4242-eu" },
});
var response = client.assignUserId(
xAlgoliaUserID = "user42",
assignUserIdParams = AssignUserIdParams(
cluster = "d4242-eu",
),
)
$response = $client->assignUserId(
'user42',
['cluster' => 'd4242-eu',
],
);
response = client.assign_user_id(
x_algolia_user_id="user42",
assign_user_id_params={
"cluster": "d4242-eu",
},
)
response = client.assign_user_id("user42", Algolia::Search::AssignUserIdParams.new(cluster: "d4242-eu"))
val response = Await.result(
client.assignUserId(
xAlgoliaUserID = "user42",
assignUserIdParams = AssignUserIdParams(
cluster = "d4242-eu"
)
),
Duration(100, "sec")
)
let response = try await client.assignUserId(
xAlgoliaUserID: "user42",
assignUserIdParams: AssignUserIdParams(cluster: "d4242-eu")
)
Adding private user data
Suppose you want to index your users’ private playlists.JavaScript
const playlists = [
{
user: "user42",
name: "My peaceful playlist",
tracks: [
// ...
],
createdAt: 1500000181,
},
{
user: "user4242",
name: "My workout playlist",
tracks: [
// ...
],
createdAt: 1500040452,
},
];
userID attribute to tag the right user. Additionally, you need to set the userID attribute as a filter at query time.
namespace Algolia;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using Algolia.Search.Clients;
using Algolia.Search.Http;
using Algolia.Search.Models.Search;
class SetSettingsThenSaveObjects
{
private static readonly List> playlists = []; // Your records
private static string GetAppIdFor(string user)
{
return ""; // Implement your own logic here
}
private static string GetIndexingApiKeyFor(string user)
{
return ""; // Implement your own logic here
}
async Task Main(string[] args)
{
foreach (var playlist in playlists)
{
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
var appId = GetAppIdFor((playlist.GetValueOrDefault("user", "") as string)!);
var apiKey = GetIndexingApiKeyFor((playlist.GetValueOrDefault("user", "") as string)!);
try
{
var client = new SearchClient(new SearchConfig(appId, apiKey));
var settings = new IndexSettings { AttributesForFaceting = ["searchable(playlistName)"] };
await client.SetSettingsAsync("", settings);
await client.SaveObjectsAsync("", playlists);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
import 'package:algolia_client_search/algolia_client_search.dart';
final playlists = []; // Your records
String getAppIDFor(String _) {
return ""; // Implement your own logic here
}
String getIndexingApiKeyFor(String _) {
return ""; // Implement your own logic here
}
void setSettingsThenSaveObjects() async {
for (final playlist in playlists) {
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
final appId = getAppIDFor(playlist["user"]);
final apiKey = getIndexingApiKeyFor(playlist["user"]);
final client = SearchClient(appId: appId, apiKey: apiKey);
final settings = IndexSettings(
attributesForFaceting: ['filterOnly(userID)'],
);
await client.setSettings(
indexName: "",
indexSettings: settings,
);
final batchParams = BatchWriteParams(
requests: playlists
.map((record) => BatchRequest(
action: Action.addObject,
body: record,
))
.toList());
await client.batch(
indexName: "",
batchWriteParams: batchParams,
);
}
}
package main
import (
"fmt"
"github.com/algolia/algoliasearch-client-go/v4/algolia/search"
)
func getAppIDFor(_ string) (string, error) {
return "", nil // Implement your logic here
}
func getIndexingApiKeyFor(_ string) (string, error) {
return "", nil // Implement your logic here
}
func setSettingsThenSaveObjects() {
playlists := []map[string]any{{ /* Your records */ }}
for _, playlist := range playlists {
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
appID, err := getAppIDFor(playlist["user"].(string))
if err != nil {
fmt.Println(err)
return
}
apiKey, err := getIndexingApiKeyFor(playlist["user"].(string))
if err != nil {
fmt.Println(err)
return
}
client, err := search.NewClient(appID, apiKey)
if err != nil {
fmt.Println(err)
return
}
settings := &search.IndexSettings{
AttributesForFaceting: []string{"filterOnly(user)"},
}
_, err = client.SetSettings(client.NewApiSetSettingsRequest(
"", settings))
if err != nil {
panic(err)
}
_, err = client.SaveObjects(
"", playlists)
if err != nil {
panic(err)
}
}
}
package com.algolia;
import com.algolia.api.SearchClient;
import com.algolia.config.*;
import com.algolia.model.search.*;
import java.util.List;
import java.util.Map;
public class setSettingsThenSaveObjects {
private static final List> playlists = List.of(
/* Your records */
);
private static String getAppIDFor(String user) {
return ""; // Implement your own logic here
}
private static String getIndexingApiKeyFor(String user) {
return ""; // Implement your own logic here
}
public static void main(String[] args) throws Exception {
playlists.forEach(playlist -> {
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
String appID = getAppIDFor((String) playlist.get("user"));
String apiKey = getIndexingApiKeyFor((String) playlist.get("user"));
try (SearchClient client = new SearchClient(appID, apiKey)) {
IndexSettings settings = new IndexSettings().setAttributesForFaceting(List.of("searchable(playlistName)"));
client.setSettings("", settings);
client.saveObjects("", playlists);
} catch (Exception e) {
System.out.println("An error occurred: " + e.getMessage());
}
});
}
}
import type { IndexSettings } from 'algoliasearch';
import { algoliasearch } from 'algoliasearch';
const playlists: Record[] = [
/* Your records */
];
const getAppIDFor = (_: string) => {
return ''; // Implement your own logic here
};
const getIndexingApiKeyFor = (_: string) => {
return ''; // Implement your own logic here
};
playlists.forEach(async (playlist) => {
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
const appID = getAppIDFor(playlist['user']);
const apiKey = getIndexingApiKeyFor(playlist['user']);
try {
const client = algoliasearch(appID, apiKey);
const settings: IndexSettings = {
attributesForFaceting: ['filterOnly(user)'],
};
await client.setSettings({ indexName: 'indexName', indexSettings: settings });
await client.saveObjects({ indexName: 'indexName', objects: playlists });
} catch (e: any) {
console.error(e);
}
});
import kotlinx.serialization.json.JsonObject
import com.algolia.client.api.SearchClient
import com.algolia.client.configuration.*
import com.algolia.client.transport.*
import com.algolia.client.extensions.*
import com.algolia.client.model.search.*
val playlists = listOf() // Your records
val getAppIDFor: (String) -> String = {
"" // Implement your own logic here
}
val getIndexingApiKeyFor: (String) -> String = {
"" // Implement your own logic here
}
suspend fun setSettingsThenSaveObjects() {
playlists.forEach { playlist ->
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
val appID = getAppIDFor(playlist["user"].toString())
val apiKey = getIndexingApiKeyFor(playlist["user"].toString())
val client = SearchClient(appID, apiKey)
val settings = IndexSettings(
attributesForFaceting = listOf("filterOnly(user)"),
)
try {
client.setSettings(
indexName = "",
indexSettings = settings,
)
client.saveObjects(
indexName = "",
objects = playlists,
)
} catch (exception: Exception) {
println(exception.message)
}
}
}
setAttributesForFaceting(['filterOnly(user)']),
];
$client->setSettings(
'',
$settings,
);
$client->saveObjects(
'',
$playlists,
);
} catch (Exception $e) {
echo $e->getMessage().PHP_EOL;
}
}
from algoliasearch.search.client import SearchClientSync
from algoliasearch.search.models.index_settings import IndexSettings
def _get_app_id_for(_user):
# Implement your own logic here
return ""
def _get_indexing_api_key_for(_user):
# Implement your own logic here
return ""
playlists = [] # Your records
for playlist in playlists:
app_id = _get_app_id_for(playlist["user"])
api_key = _get_indexing_api_key_for(playlist["user"])
_client = SearchClientSync(app_id, api_key)
settings = IndexSettings(attributes_for_faceting=["filterOnly(user)"])
try:
_client.set_settings(
index_name="",
index_settings=settings,
)
_client.save_objects(
index_name="",
objects=playlists,
)
except Exception as e:
print(f"Error: {e}")
require "algolia"
def get_app_id_for(_user)
# Implement your own logic here
""
end
def get_indexing_api_key_for(_user)
# Implement your own logic here
""
end
# Your records
playlists = []
playlists.each do |playlist|
begin
app_id = get_app_id_for(playlist["user"])
api_key = get_indexing_api_key_for(playlist["user"])
client = Algolia::SearchClient.create(app_id, api_key)
settings = Algolia::Search::IndexSettings.new(
attributes_for_faceting: ["filterOnly(user)"]
)
client.set_settings("", settings)
client.save_objects("", playlists)
rescue Exception => e
puts("An error occurred: #{e}")
end
end
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import algoliasearch.api.SearchClient
import algoliasearch.config.*
import algoliasearch.extension.SearchClientExtensions
import algoliasearch.search.IndexSettings
val getAppIDFor: String => String = _ => {
"" // Implement your own logic here
}
val getIndexingApiKeyFor: String => String = _ => {
"" // Implement your own logic here
}
def setSettingsThenSaveObjects(): Future[Unit] = {
val playlists: Seq[Map[String, Any]] = Seq() // Your records
playlists.foreach { playlist =>
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
val appID = getAppIDFor(playlist("user").toString)
val apiKey = getIndexingApiKeyFor(playlist("user").toString)
val client = SearchClient(appID, apiKey)
val settings = IndexSettings(
attributesForFaceting = Some(Seq("filterOnly(user)"))
)
Await.result(
client.setSettings(
indexName = "",
indexSettings = settings
),
Duration(5, "sec")
)
Await.result(
client.saveObjects(
indexName = "",
objects = playlists
),
Duration(5, "sec")
)
}
Future.unit
}
import Foundation
#if os(Linux) // For linux interop
import FoundationNetworking
#endif
import Core
import Search
let playlists: [[String: AnyCodable]] = [ /* Your records */ ]
let getAppIDFor = { (_: String) in "" } // Implement your own logic here
let getIndexingApiKeyFor = { (_: String) in "" } // Implement your own logic here
func setSettingsThenSaveObjects() async throws {
for playlist in playlists {
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
let appID = getAppIDFor(playlist["user"]?.value as! String)
let apiKey = getIndexingApiKeyFor(playlist["user"]?.value as! String)
do {
let client = try SearchClient(appID: appID, apiKey: apiKey)
let settings = IndexSettings(
attributesForFaceting: ["filterOnly(user)"]
)
try await client.setSettings(indexName: "", indexSettings: settings)
try await client.saveObjects(indexName: "", objects: playlists)
} catch {
print(error)
}
}
}
X-Algolia-User-ID header you send at query time. The engine automatically adds an extra attribute __userID__ inside records to identify the userID associated with each record.
namespace Algolia;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using Algolia.Search.Clients;
using Algolia.Search.Http;
using Algolia.Search.Models.Search;
class SetHeaderUserIDThenSaveObjects
{
private static readonly List> playlists = []; // Your records
async Task Main(string[] args)
{
var client = new SearchClient(new SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY"));
foreach (var playlist in playlists)
{
try
{
var playlistUserID = playlist.GetValueOrDefault("userID", "") as string;
await client.SaveObjectsAsync(
"",
playlists,
false,
1000,
new RequestOptionBuilder().AddExtraHeader("X-Algolia-User-ID", playlistUserID).Build()
);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
import 'package:algolia_client_search/algolia_client_search.dart';
final playlists = []; // Your records
void setHeaderUserIDThenSaveObjects() async {
final client =
SearchClient(appId: 'ALGOLIA_APPLICATION_ID', apiKey: 'ALGOLIA_API_KEY');
for (final playlist in playlists) {
final playlistUserID = playlist["userID"];
final batchParams = BatchWriteParams(
requests: playlists
.map((record) => BatchRequest(
action: Action.addObject,
body: record,
))
.toList());
await client.batch(
indexName: "",
batchWriteParams: batchParams,
requestOptions: RequestOptions(
headers: {
'X-Algolia-User-ID': playlistUserID,
},
));
}
}
package main
import "github.com/algolia/algoliasearch-client-go/v4/algolia/search"
func setHeaderUserIDThenSaveObjects() {
playlists := []map[string]any{{ /* Your records */ }}
client, err := search.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
if err != nil {
// The client can fail to initialize if you pass an invalid parameter.
panic(err)
}
for _, playlist := range playlists {
playlistUserID := playlist["userID"]
_, err := client.SaveObjects(
"",
playlists,
search.WithWaitForTasks(false),
search.WithBatchSize(1000),
search.WithHeaderParam("X-Algolia-User-ID", playlistUserID),
)
if err != nil {
panic(err)
}
}
}
package com.algolia;
import com.algolia.api.SearchClient;
import com.algolia.config.*;
import com.algolia.model.search.*;
import java.util.List;
import java.util.Map;
public class setHeaderUserIDThenSaveObjects {
private static final List> playlists = List.of(
/* Your records */
);
public static void main(String[] args) throws Exception {
try (SearchClient client = new SearchClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")) {
playlists.forEach(playlist -> {
String playlistUserID = (String) playlist.get("userID");
client.saveObjects(
"",
playlists,
false,
1000,
new RequestOptions().addExtraHeader("X-Algolia-User-ID", playlistUserID)
);
});
} catch (Exception e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
}
import { algoliasearch } from 'algoliasearch';
const playlists: Record[] = [
/* Your records */
];
const client = algoliasearch('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY');
playlists.forEach(async (playlist) => {
try {
const playlistUserID = playlist['userID'];
await client.saveObjects(
{ indexName: 'indexName', objects: playlists, waitForTasks: false, batchSize: 1000 },
{
headers: { 'X-Algolia-User-ID': playlistUserID },
},
);
} catch (e: any) {
console.error(e);
}
});
import kotlinx.serialization.json.JsonObject
import com.algolia.client.api.SearchClient
import com.algolia.client.configuration.*
import com.algolia.client.transport.*
import com.algolia.client.extensions.*
import com.algolia.client.model.search.*
suspend fun setHeaderUserIDThenSaveObjects() {
val playlists: List = listOf() // Your records
val client = SearchClient(appId = "ALGOLIA_APPLICATION_ID", apiKey = "ALGOLIA_API_KEY")
playlists.forEach { playlist ->
val playlistUserID = playlist["userID"].toString()
try {
client.saveObjects(
indexName = "",
objects = playlists,
waitForTasks = false,
batchSize = 1000,
requestOptions = RequestOptions(
headers = buildMap {
put("X-Algolia-User-ID", playlistUserID)
},
),
)
} catch (exception: Exception) {
println(exception.message)
}
}
}
saveObjects(
'',
$playlists,
false,
1000,
[
'headers' => [
'X-Algolia-User-ID' => $playlistUserID,
],
]
);
} catch (Exception $e) {
echo $e->getMessage().PHP_EOL;
}
}
from json import loads
from algoliasearch.search.client import SearchClientSync
playlists = [] # Your records
_client = SearchClientSync("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
for playlist in playlists:
try:
playlist_user_id = playlist["userID"]
_client.save_objects(
index_name="",
objects=playlists,
wait_for_tasks=False,
batch_size=1000,
request_options={
"headers": loads("""{"X-Algolia-User-ID":playlistUserID}"""),
},
)
except Exception as e:
print(f"Error: {e}")
require "algolia"
# Your records
playlists = []
client = Algolia::SearchClient.create("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
playlists.each do |playlist|
playlist_user_id = playlist["userID"]
client.save_objects(
"",
playlists,
false,
1000,
{:header_params => {"X-Algolia-User-ID" => playlist_user_id}}
)
end
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import algoliasearch.api.SearchClient
import algoliasearch.config.*
import algoliasearch.extension.SearchClientExtensions
def setHeaderUserIDThenSaveObjects(): Future[Unit] = {
val playlists: Seq[Map[String, Any]] = Seq() // Your records
val client = SearchClient(appId = "ALGOLIA_APPLICATION_ID", apiKey = "ALGOLIA_API_KEY")
playlists.foreach { playlist =>
val playlistUserID = playlist("userID").toString
Await.result(
client.saveObjects(
indexName = "",
objects = playlists,
waitForTasks = false,
batchSize = 1000,
requestOptions = Some(
RequestOptions
.builder()
.withHeader("X-Algolia-User-ID", "playlistUserID")
.build()
)
),
Duration(5, "sec")
)
}
Future.unit
}
import Foundation
#if os(Linux) // For linux interop
import FoundationNetworking
#endif
import Core
import Search
func setHeaderUserIDThenSaveObjects() async throws {
let playlists: [[String: AnyCodable]] = [ /* Your records */ ]
let client = try SearchClient(appID: "ALGOLIA_APPLICATION_ID", apiKey: "ALGOLIA_API_KEY")
for playlist in playlists {
do {
let playlistUserID = playlist["userID"]?.value as! String
try await client.saveObjects(
indexName: "",
objects: playlists,
waitForTasks: false,
batchSize: 1000,
requestOptions: RequestOptions(
headers: ["X-Algolia-User-ID": playlistUserID]
)
)
} catch {
print(error)
}
}
}
For simplicity’s sake, the preceding snippets add records one by one.
For better performance, you should group your records by
userID first, then batch them.Adding public data
If you decide you want to index public playlists as well.JavaScript
const playlists = [
{
user: "public",
name: "Hot 100 Billboard Charts",
tracks: [
// ...
],
createdAt: 1500240452,
},
];
userID attribute. Then, you need to filter on that value to search for public records.
namespace Algolia;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using Algolia.Search.Clients;
using Algolia.Search.Http;
using Algolia.Search.Models.Search;
class SaveObjectsMcm
{
private readonly List> playlists = []; // Your records
private static List> GetAllAppIdConfigurations()
{
return
[ /* A list of your MCM AppID/ApiKey pairs */
];
}
async Task Main(string[] args)
{
// Fetch from your own data storage and with your own code
// the list of application IDs and API keys to target each cluster
var configurations = GetAllAppIdConfigurations();
// Send the records to each cluster
foreach (var config in configurations)
{
try
{
var client = new SearchClient(
new SearchConfig(
config.GetValueOrDefault("appID", ""),
config.GetValueOrDefault("apiKey", "")
)
);
await client.SaveObjectsAsync("", playlists);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
import 'package:algolia_client_search/algolia_client_search.dart';
List> getAllAppIDConfigurations() {
return [/* A list of your MCM AppID/ApiKey pairs */];
}
List playlists = [/* Your records */];
void saveObjectsMCM() async {
final configurations = getAllAppIDConfigurations();
for (var configuration in configurations) {
final appId = configuration['appID'] ?? "";
final apiKey = configuration['apiKey'] ?? "";
final client = SearchClient(appId: appId, apiKey: apiKey);
try {
final batchParams = BatchWriteParams(
requests: playlists
.map((record) => BatchRequest(
action: Action.addObject,
body: record,
))
.toList());
await client.batch(
indexName: "",
batchWriteParams: batchParams,
);
} catch (e) {
throw Exception('Error for appID $appId: $e');
}
}
}
package main
import (
"fmt"
"github.com/algolia/algoliasearch-client-go/v4/algolia/search"
)
func getAllAppIDConfigurations() ([]struct{ appID, apiKey string }, error) {
return []struct{ appID, apiKey string }{ /* A list of your MCM AppID/ApiKey pairs */ }, nil
}
func saveObjectsMCM() {
playlists := []map[string]any{{ /* Your records */ }}
// Fetch from your own data storage and with your own code
// the list of application IDs and API keys to target each cluster
configurations, err := getAllAppIDConfigurations()
if err != nil {
fmt.Println(err)
return
}
// Send the records to each cluster
for _, configuration := range configurations {
client, err := search.NewClient(configuration.appID, configuration.apiKey)
if err != nil {
fmt.Println(err)
return
}
_, err = client.SaveObjects(
"", playlists)
if err != nil {
panic(err)
}
}
}
package com.algolia;
import com.algolia.api.SearchClient;
import com.algolia.config.*;
import com.algolia.model.search.*;
import java.util.List;
import java.util.Map;
public class saveObjectsMCM {
private static final List> playlists = List.of(
/* Your records */
);
private static List> getAllAppIDConfigurations() {
return List.of(
/* A list of your MCM AppID/ApiKey pairs */
);
}
public static void main(String[] args) throws Exception {
// Fetch from your own data storage and with your own code
// the list of application IDs and API keys to target each cluster
var configurations = getAllAppIDConfigurations();
// Send the records to each cluster
configurations.forEach(config -> {
try (SearchClient client = new SearchClient(config.get("appID"), config.get("apiKey"))) {
client.saveObjects("", playlists);
} catch (Exception e) {
System.out.println("An error occurred: " + e.getMessage());
}
});
}
}
import { algoliasearch } from 'algoliasearch';
const getAllAppIDConfigurations = (): Record[] => {
return [
/* A list of your MCM AppID/ApiKey pairs */
];
};
const playlists: Record[] = [
/* Your records */
];
// Fetch from your own data storage and with your own code
// the list of application IDs and API keys to target each cluster
const configurations = getAllAppIDConfigurations();
// Send the records to each cluster
Object.keys(configurations).forEach(async (appID) => {
try {
const client = algoliasearch(appID, configurations[appID]);
await client.saveObjects({ indexName: 'indexName', objects: playlists });
} catch (e: any) {
console.error(e);
}
});
import kotlinx.serialization.json.JsonObject
import com.algolia.client.api.SearchClient
import com.algolia.client.configuration.*
import com.algolia.client.transport.*
import com.algolia.client.extensions.*
import com.algolia.client.model.search.*
val getAllAppIDConfigurations: () -> Map = {
mapOf() // A map of your MCM AppID/ApiKey pairs
}
suspend fun saveObjectsMCM() {
val playlists: List = listOf() // Your records
val configurations = getAllAppIDConfigurations()
configurations.map { (appID, apiKey) ->
val client = SearchClient(appID, apiKey)
try {
client.saveObjects(
indexName = "",
objects = playlists,
)
} catch (e: Exception) {
throw Exception("Error for appID $appID: ${e.message}")
}
}
}
saveObjects(
'',
$playlists,
);
} catch (Exception $e) {
echo $e->getMessage().PHP_EOL;
}
}
from algoliasearch.search.client import SearchClientSync
def _get_all_app_id_configurations():
return [] # A list of your MCM AppID/ApiKey pairs
playlists = [] # Your records
# Fetch from your own data storage and with your own code
# the list of application IDs and API keys to target each cluster
configurations = _get_all_app_id_configurations()
# Send the records to each cluster
for appID, apiKey in configurations:
try:
_client = SearchClientSync(appID, apiKey)
_client.save_objects(
index_name="",
objects=playlists,
)
except Exception as e:
print(f"Error: {e}")
require "algolia"
def get_all_app_id_configurations
# A list of your MCM AppID/ApiKey pairs
[]
end
# Your records
playlists = []
# Fetch from your own data storage and with your own code
# the list of application IDs and API keys to target each cluster
configurations = get_all_app_id_configurations
# Send the records to each cluster
configurations.each do |appID, apiKey|
begin
client = Algolia::SearchClient.create(appID, apiKey)
client.save_objects("", playlists)
rescue Exception => e
puts("An error occurred: #{e}")
end
end
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import algoliasearch.api.SearchClient
import algoliasearch.config.*
import algoliasearch.extension.SearchClientExtensions
import algoliasearch.config.RequestOptions
val getAllAppIDConfigurations: () => Map[String, String] = () => {
Map( /* A map of your MCM AppID/ApiKey pairs */ )
}
val playlists: Seq[Any] = Seq( /* Your records */ )
def saveObjectsMCM(): Future[Unit] = {
val configurations = getAllAppIDConfigurations()
Future
.sequence {
configurations.map { case (appID, apiKey) =>
val client = new SearchClient(appID, apiKey)
client
.saveObjects(
indexName = "",
objects = playlists
)
.recover { case ex: Exception =>
println(s"Error for appID $appID: ${ex.getMessage}")
}
}
}
.map(_ => ())
}
import Foundation
#if os(Linux) // For linux interop
import FoundationNetworking
#endif
import Core
import Search
let getAllAppIDConfigurations: () -> [(String, String)] = {
[ /* A list of your MCM AppID/ApiKey pairs */ ]
}
func saveObjectsMCM() async throws {
let playlists: [[String: AnyCodable]] = [ /* Your records */ ]
// Fetch from your own data storage and with your own code
// the list of application IDs and API keys to target each cluster
let configurations = getAllAppIDConfigurations()
// Send the records to each cluster
for (appID, apiKey) in configurations {
do {
let client = try SearchClient(appID: appID, apiKey: apiKey)
try await client.saveObjects(indexName: "", objects: playlists)
} catch {
print(error)
}
}
}
userID value * to flag records as public, allowing all users to see them. Public records are automatically replicated on all clusters to avoid network latency during search.
namespace Algolia;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using Algolia.Search.Clients;
using Algolia.Search.Http;
using Algolia.Search.Models.Search;
class SaveObjectsPublicUser
{
private static readonly List> playlists = []; // Your records
async Task Main(string[] args)
{
var client = new SearchClient(new SearchConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY"));
await client.SaveObjectsAsync(
"",
playlists,
false,
1000,
new RequestOptionBuilder().AddExtraHeader("X-Algolia-User-ID", "*").Build()
);
}
}
import 'package:algolia_client_search/algolia_client_search.dart';
final playlists = [/* Your records */];
void saveObjectsPublicUser() async {
final client =
SearchClient(appId: 'ALGOLIA_APPLICATION_ID', apiKey: 'ALGOLIA_API_KEY');
final batchParams = BatchWriteParams(
requests: playlists
.map((record) => BatchRequest(
action: Action.addObject,
body: record,
))
.toList());
await client.batch(
indexName: "",
batchWriteParams: batchParams,
requestOptions: RequestOptions(
headers: {
'X-Algolia-User-ID': "*",
},
));
}
package main
import "github.com/algolia/algoliasearch-client-go/v4/algolia/search"
func saveObjectsPublicUser() {
playlists := []map[string]any{{ /* Your records */ }}
client, err := search.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
if err != nil {
// The client can fail to initialize if you pass an invalid parameter.
panic(err)
}
_, err = client.SaveObjects(
"",
playlists,
search.WithWaitForTasks(false),
search.WithBatchSize(1000),
search.WithHeaderParam("X-Algolia-User-ID", "*"),
)
if err != nil {
panic(err)
}
}
package com.algolia;
import com.algolia.api.SearchClient;
import com.algolia.config.*;
import com.algolia.model.search.*;
import java.util.List;
import java.util.Map;
public class saveObjectsPublicUser {
private static final List> playlists = List.of(
/* Your records */
);
public static void main(String[] args) throws Exception {
try (SearchClient client = new SearchClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")) {
client.saveObjects("", playlists, false, 1000, new RequestOptions().addExtraHeader("X-Algolia-User-ID", "*"));
} catch (Exception e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
}
import { algoliasearch } from 'algoliasearch';
const playlists: Record[] = []; // Your records
const client = algoliasearch('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY');
await client.saveObjects(
{ indexName: 'indexName', objects: playlists, waitForTasks: false, batchSize: 1000 },
{
headers: { 'X-Algolia-User-ID': '*' },
},
);
import kotlinx.serialization.json.JsonObject
import com.algolia.client.api.SearchClient
import com.algolia.client.configuration.*
import com.algolia.client.transport.*
import com.algolia.client.extensions.*
import com.algolia.client.model.search.*
import com.algolia.client.transport.RequestOptions
suspend fun saveObjectsPublicUser() {
val playlists: List = listOf() // Your records
val client = SearchClient(appId = "ALGOLIA_APPLICATION_ID", apiKey = "ALGOLIA_API_KEY")
client.saveObjects(
indexName = "",
objects = playlists,
waitForTasks = false,
batchSize = 1000,
requestOptions = RequestOptions(
headers = buildMap {
put("X-Algolia-User-ID", "*")
},
),
)
}
saveObjects(
'',
$playlists,
false,
1000,
[
'headers' => [
'X-Algolia-User-ID' => '*',
],
]
);
from json import loads
from algoliasearch.search.client import SearchClientSync
playlists = [] # Your records
_client = SearchClientSync("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
_client.save_objects(
index_name="",
objects=playlists,
wait_for_tasks=False,
batch_size=1000,
request_options={
"headers": loads("""{"X-Algolia-User-ID":"*"}"""),
},
)
require "algolia"
# Your records
playlists = []
client = Algolia::SearchClient.create("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
client.save_objects("", playlists, false, 1000, {:header_params => {"X-Algolia-User-ID" => "*"}})
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import algoliasearch.api.SearchClient
import algoliasearch.config.*
import algoliasearch.extension.SearchClientExtensions
import algoliasearch.config.RequestOptions
def saveObjectsPublicUser(): Future[Unit] = {
val playlists: Seq[Any] = Seq() // Your records
val client = SearchClient(appId = "ALGOLIA_APPLICATION_ID", apiKey = "ALGOLIA_API_KEY")
Await.result(
client
.saveObjects(
indexName = "",
objects = playlists,
waitForTasks = false,
batchSize = 1000,
requestOptions = Some(
RequestOptions
.builder()
.withHeader("X-Algolia-User-ID", "*")
.build()
)
)
.map(_ => Future.unit),
Duration(5, "sec")
)
}
import Foundation
#if os(Linux) // For linux interop
import FoundationNetworking
#endif
import Core
import Search
func saveObjectsPublicUser() async throws {
let playlists: [[String: AnyCodable]] = [] // Your records
let client = try SearchClient(appID: "ALGOLIA_APPLICATION_ID", apiKey: "ALGOLIA_API_KEY")
try await client.saveObjects(
indexName: "",
objects: playlists,
waitForTasks: false,
batchSize: 1000,
requestOptions: RequestOptions(
headers: ["X-Algolia-User-ID": "*"]
)
)
}
Searching the data
Without MCM, you need to manually handle the filtering logic to filter on private data for a specific user and public data.namespace Algolia;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using Algolia.Search.Clients;
using Algolia.Search.Http;
using Algolia.Search.Models.Search;
class McmSearchWithout
{
private static string GetAppIdFor(string user)
{
return ""; // Implement your own logic here
}
private static string GetIndexingApiKeyFor(string user)
{
return ""; // Implement your own logic here
}
async Task Main(string[] args)
{
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
var appId = GetAppIdFor("user42");
var apiKey = GetIndexingApiKeyFor("user42");
var client = new SearchClient(new SearchConfig(appId, apiKey));
var searchParams = new SearchParams(
new SearchParamsObject
{
Query = "",
FacetFilters = new FacetFilters(
[new FacetFilters("user:user42"), new FacetFilters("user:public")]
),
}
);
await client.SearchSingleIndexAsync("", searchParams);
}
}
import 'package:algolia_client_search/algolia_client_search.dart';
String getAppIDFor(String _) {
return ""; // Implement your own logic here
}
String getIndexingApiKeyFor(String _) {
return ""; // Implement your own logic here
}
void mcmSearchWithout() async {
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
final appId = getAppIDFor("user42");
final apiKey = getIndexingApiKeyFor("user42");
final client = SearchClient(appId: appId, apiKey: apiKey);
final searchParams = SearchParamsObject(
query: "",
facetFilters: ["user:user42", "user:public"]);
await client.searchSingleIndex(
indexName: "",
searchParams: searchParams,
);
}
package main
import (
"fmt"
"github.com/algolia/algoliasearch-client-go/v4/algolia/search"
)
func mcmSearchWithout() {
getAppIDFor := func(_ string) (string, error) {
return "", nil // Implement your logic here
}
getIndexingApiKeyFor := func(_ string) (string, error) {
return "", nil // Implement your logic here
}
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
appID, err := getAppIDFor("user42")
if err != nil {
fmt.Println(err)
return
}
apiKey, err := getIndexingApiKeyFor("user42")
if err != nil {
fmt.Println(err)
return
}
client, err := search.NewClient(appID, apiKey)
if err != nil {
fmt.Println(err)
return
}
searchParams := search.SearchParamsObjectAsSearchParams(
search.NewSearchParamsObject().
SetQuery("").
SetFacetFilters(
search.ArrayOfFacetFiltersAsFacetFilters(
[]search.FacetFilters{
*search.StringAsFacetFilters("user:user42"),
*search.StringAsFacetFilters("user:public"),
},
),
),
)
_, err = client.SearchSingleIndex(client.NewApiSearchSingleIndexRequest(
"").WithSearchParams(searchParams))
if err != nil {
panic(err)
}
}
package com.algolia;
import com.algolia.api.SearchClient;
import com.algolia.config.*;
import com.algolia.model.search.*;
import java.util.List;
public class mcmSearchWithout {
private static String getAppIDFor(String user) {
return ""; // Implement your own logic here
}
private static String getIndexingApiKeyFor(String user) {
return ""; // Implement your own logic here
}
public static void main(String[] args) throws Exception {
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
String appID = getAppIDFor("user42");
String apiKey = getIndexingApiKeyFor("user42");
try (SearchClient client = new SearchClient(appID, apiKey)) {
SearchParams searchParams = new SearchParamsObject()
.setQuery("")
.setFacetFilters(FacetFilters.of(List.of(FacetFilters.of("user:user42"), FacetFilters.of("user:public"))));
client.searchSingleIndex("", searchParams, Hit.class);
} catch (Exception e) {
System.out.println("An error occurred: " + e.getMessage());
}
}
}
import type { SearchParams } from 'algoliasearch';
import { algoliasearch } from 'algoliasearch';
const getAppIDFor = (_: string) => {
return ''; // Implement your own logic here
};
const getIndexingApiKeyFor = (_: string) => {
return ''; // Implement your own logic here
};
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
const appID = getAppIDFor('user42');
const apiKey = getIndexingApiKeyFor('user42');
const client = algoliasearch(appID, apiKey);
const searchParams: SearchParams = {
query: '',
facetFilters: ['user:user42', 'user:public'],
};
await client.searchSingleIndex({ indexName: 'indexName', searchParams: searchParams });
import com.algolia.client.api.SearchClient
import com.algolia.client.configuration.*
import com.algolia.client.transport.*
import com.algolia.client.extensions.*
import com.algolia.client.model.search.*
suspend fun mcmSearchWithout() {
val getAppIDFor: (String) -> String = {
"" // Implement your own logic here
}
val getIndexingApiKeyFor: (String) -> String = {
"" // Implement your own logic here
}
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
val appID = getAppIDFor("user42")
val apiKey = getIndexingApiKeyFor("user42")
val client = SearchClient(appID, apiKey)
val searchParams = SearchParamsObject(
query = "",
facetFilters = FacetFilters.of(
listOf(
FacetFilters.of("user:user42"),
FacetFilters.of("user:public"),
),
),
)
client.searchSingleIndex(
indexName = "",
searchParams = searchParams,
)
}
setQuery('')
->setFacetFilters(['user:user42', 'user:public'])
;
$client->searchSingleIndex(
'',
$searchParams,
);
from algoliasearch.search.client import SearchClientSync
def _get_app_id_for(_user):
# Implement your own logic here
return ""
def _get_indexing_api_key_for(_user):
# Implement your own logic here
return ""
app_id = _get_app_id_for("user42")
api_key = _get_indexing_api_key_for("user42")
_client = SearchClientSync(app_id, api_key)
search_params = {
"query": "",
"facetFilters": ["user:user42", "user:public"],
}
_client.search_single_index(
index_name="",
search_params=search_params,
)
import(time)
require "algolia"
def get_app_id_for(_user)
# Implement your own logic here
""
end
def get_indexing_api_key_for(_user)
# Implement your own logic here
""
end
app_id = get_app_id_for("user42")
api_key = get_indexing_api_key_for("user42")
client = Algolia::SearchClient.create(app_id, api_key)
search_params = Algolia::Search::SearchParamsObject.new(
query: "",
facet_filters: %w[user:user42 user:public]
)
client.search_single_index("", search_params)
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import algoliasearch.api.SearchClient
import algoliasearch.config.*
import algoliasearch.extension.SearchClientExtensions
import algoliasearch.search.{FacetFilters, SearchParamsObject}
def mcmSearchWithout(): Future[Unit] = {
val getAppIDFor: String => String = _ => {
"" // Implement your own logic here
}
val getIndexingApiKeyFor: String => String = _ => {
"" // Implement your own logic here
}
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
val appID = getAppIDFor("user42")
val apiKey = getIndexingApiKeyFor("user42")
val client = SearchClient(appID, apiKey)
val searchParams = SearchParamsObject(
query = Some(""),
facetFilters = Some(
FacetFilters.SeqOfFacetFilters(
Seq(
FacetFilters.StringValue("user:user42"),
FacetFilters.StringValue("user:public")
)
)
)
)
client
.searchSingleIndex(
indexName = "",
searchParams = Some(searchParams)
)
.map { response =>
println(response)
}
.recover { case ex: Exception =>
println(s"An error occurred: ${ex.getMessage}")
}
}
import Foundation
#if os(Linux) // For linux interop
import FoundationNetworking
#endif
import Core
import Search
func mcmSearchWithout() async throws {
let getAppIDFor = { (_: String) in "" } // Implement your own logic here
let getIndexingApiKeyFor = { (_: String) in "" } // Implement your own logic here
// Fetch from your own data storage and with your own code
// the associated application ID and API key for this user
let appID = getAppIDFor("user42")
let apiKey = getIndexingApiKeyFor("user42")
let client = try SearchClient(appID: appID, apiKey: apiKey)
let searchParams = SearchSearchParams.searchSearchParamsObject(
SearchSearchParamsObject(
query: "",
facetFilters: .arrayOfSearchFacetFilters([.string("user:user42"), .string("user:public")])
)
)
let response: SearchResponse = try await client.searchSingleIndex(
indexName: "",
searchParams: searchParams
)
print(response)
}
userID (with the X-Algolia-User-ID header) that the query targets, so it can route the request to the right cluster. It automatically adds the right filters to retrieve both the user’s data and public data.
var response = await client.SearchSingleIndexAsync(
"INDEX_NAME",
new SearchParams(new SearchParamsObject { Query = "peace" }),
new RequestOptionBuilder().AddExtraHeader("X-Algolia-User-ID", "user42").Build()
);
final response = await client.searchSingleIndex(
indexName: "INDEX_NAME",
searchParams: SearchParamsObject(query: "peace"),
requestOptions: RequestOptions(headers: {'X-Algolia-User-ID': 'user42'}),
);
response, err := client.SearchSingleIndex(client.NewApiSearchSingleIndexRequest(
"INDEX_NAME").WithSearchParams(search.SearchParamsObjectAsSearchParams(
search.NewEmptySearchParamsObject().SetQuery("peace"))), search.WithHeaderParam("X-Algolia-User-ID", "user42"))
if err != nil {
// handle the eventual error
panic(err)
}
client.searchSingleIndex(
"INDEX_NAME",
new SearchParamsObject().setQuery("peace"),
Hit.class,
new RequestOptions().addExtraHeader("X-Algolia-User-ID", "user42")
);
const response = await client.searchSingleIndex(
{ indexName: "playlists", searchParams: { query: "peace" } },
{
headers: { "X-Algolia-User-ID": "user42" },
},
);
var response = client.searchSingleIndex(
indexName = "INDEX_NAME",
searchParams = SearchParamsObject(
query = "peace",
),
requestOptions = RequestOptions(
headers = buildMap {
put("X-Algolia-User-ID", "user42")
},
),
)
$response = $client->searchSingleIndex(
'INDEX_NAME',
['query' => 'peace',
],
[
'headers' => [
'X-Algolia-User-ID' => 'user42',
],
]
);
response = client.search_single_index(
index_name="INDEX_NAME",
search_params={
"query": "peace",
},
request_options={
"headers": loads("""{"X-Algolia-User-ID":"user42"}"""),
},
)
response = client.search_single_index(
"INDEX_NAME",
Algolia::Search::SearchParamsObject.new(query: "peace"),
{:header_params => {"X-Algolia-User-ID" => "user42"}}
)
val response = Await.result(
client.searchSingleIndex(
indexName = "INDEX_NAME",
searchParams = Some(
SearchParamsObject(
query = Some("peace")
)
),
requestOptions = Some(
RequestOptions
.builder()
.withHeader("X-Algolia-User-ID", "user42")
.build()
)
),
Duration(100, "sec")
)
let response: SearchResponse = try await client.searchSingleIndex(
indexName: "INDEX_NAME",
searchParams: SearchSearchParams.searchSearchParamsObject(SearchSearchParamsObject(query: "peace")),
requestOptions: RequestOptions(
headers: ["X-Algolia-User-ID": "user42"]
)
)
Accessing secured data
You can’t rely on filters to select what data to return to a specific user because users can change these parameters. If all you have to pick specific data is query time filters, anyone can alter these to access the data of another user. To properly restrict access of a user to only their data (and the public data), you need to use secured API keys. Without MCM, you need to set the filters to authorize manually.var response = client.GenerateSecuredApiKey(
"ALGOLIA_SEARCH_API_KEY",
new SecuredApiKeyRestrictions { Filters = "user:user42 AND user:public" }
);
final response = client.generateSecuredApiKey(
parentApiKey: "ALGOLIA_SEARCH_API_KEY",
restrictions: SecuredApiKeyRestrictions(
filters: "user:user42 AND user:public",
),
);
response, err := client.GenerateSecuredApiKey(
"ALGOLIA_SEARCH_API_KEY",
search.NewEmptySecuredApiKeyRestrictions().SetFilters("user:user42 AND user:public"))
if err != nil {
// handle the eventual error
panic(err)
}
client.generateSecuredApiKey("ALGOLIA_SEARCH_API_KEY", new SecuredApiKeyRestrictions().setFilters("user:user42 AND user:public"));
const response = client.generateSecuredApiKey({
parentApiKey: "ALGOLIA_SEARCH_API_KEY",
restrictions: { filters: "user:user42 AND user:public" },
});
var response = client.generateSecuredApiKey(
parentApiKey = "ALGOLIA_SEARCH_API_KEY",
restrictions = SecuredApiKeyRestrictions(
filters = "user:user42 AND user:public",
),
)
$response = $client->generateSecuredApiKey(
'ALGOLIA_SEARCH_API_KEY',
['filters' => 'user:user42 AND user:public',
],
);
response = client.generate_secured_api_key(
parent_api_key="ALGOLIA_SEARCH_API_KEY",
restrictions={
"filters": "user:user42 AND user:public",
},
)
response = client.generate_secured_api_key(
"ALGOLIA_SEARCH_API_KEY",
Algolia::Search::SecuredApiKeyRestrictions.new(filters: "user:user42 AND user:public")
)
val response = client.generateSecuredApiKey(
parentApiKey = "ALGOLIA_SEARCH_API_KEY",
restrictions = SecuredApiKeyRestrictions(
filters = Some("user:user42 AND user:public")
)
)
let response = try client.generateSecuredApiKey(
parentApiKey: "ALGOLIA_SEARCH_API_KEY",
restrictions: SecuredApiKeyRestrictions(filters: "user:user42 AND user:public")
)
userToken. It automatically adds the right filters to authorize.
var response = client.GenerateSecuredApiKey(
"ALGOLIA_SEARCH_API_KEY",
new SecuredApiKeyRestrictions { UserToken = "user42" }
);
final response = client.generateSecuredApiKey(
parentApiKey: "ALGOLIA_SEARCH_API_KEY",
restrictions: SecuredApiKeyRestrictions(userToken: "user42"),
);
response, err := client.GenerateSecuredApiKey(
"ALGOLIA_SEARCH_API_KEY",
search.NewEmptySecuredApiKeyRestrictions().SetUserToken("user42"))
if err != nil {
// handle the eventual error
panic(err)
}
client.generateSecuredApiKey("ALGOLIA_SEARCH_API_KEY", new SecuredApiKeyRestrictions().setUserToken("user42"));
const response = client.generateSecuredApiKey({
parentApiKey: "ALGOLIA_SEARCH_API_KEY",
restrictions: { userToken: "user42" },
});
var response = client.generateSecuredApiKey(
parentApiKey = "ALGOLIA_SEARCH_API_KEY",
restrictions = SecuredApiKeyRestrictions(
userToken = "user42",
),
)
$response = $client->generateSecuredApiKey(
'ALGOLIA_SEARCH_API_KEY',
['userToken' => 'user42',
],
);
response = client.generate_secured_api_key(
parent_api_key="ALGOLIA_SEARCH_API_KEY",
restrictions={
"userToken": "user42",
},
)
response = client.generate_secured_api_key(
"ALGOLIA_SEARCH_API_KEY",
Algolia::Search::SecuredApiKeyRestrictions.new(user_token: "user42")
)
val response = client.generateSecuredApiKey(
parentApiKey = "ALGOLIA_SEARCH_API_KEY",
restrictions = SecuredApiKeyRestrictions(
userToken = Some("user42")
)
)
let response = try client.generateSecuredApiKey(
parentApiKey: "ALGOLIA_SEARCH_API_KEY",
restrictions: SecuredApiKeyRestrictions(userToken: "user42")
)
With MCM, you always need to provide the
X-Algolia-User-ID header, even when the query contains the userToken parameter.
The header is required to route the requests efficiently.Index configuration and API keys
When performing actions that have global impact on all clusters, such as usingaddApiKey or setSettings, you don’t need to provide the X-Algolia-User-ID header.