Curated Recommendations Client
Fetches personalized content recommendations from the Merino Service. Merino Curated Recommendations API Docs
The API for the CuratedRecommendationsClient
can be found in the Mozilla Rust components Kotlin API Reference and Swift API Reference.
Prerequisites
Ensure that Viaduct is initialized during application startup, as it is used for making network requests.
Async
The Curated Recommendations API is synchronous, meaning calling it directly will block the current thread. To mitigate this, consumers should wrap the API in an async implementation.
Importing the Client
import mozilla.appservices.merino.curatedrecommendations.CuratedRecommendationsClient
import mozilla.appservices.merino.curatedrecommendations.CuratedRecommendationsRequest
import mozilla.appservices.merino.curatedrecommendations.CuratedRecommendationsResponse
import mozilla.appservices.merino.curatedrecommendations.CuratedRecommendationsError
import MozillaAppServices
Initializing the Curated Recommendations Client
The CuratedRecommendationsClient
requires a userAgentHeader
and optionally accepts a baseHost
for customizing the target environment. By default, it uses the production host.
val client = CuratedRecommendationsClient(
baseHost = "https://merino.services.mozilla.com",
userAgentHeader = "Mozilla/5.0"
)
let client = CuratedRecommendationsClient(
baseHost: "https://merino.services.mozilla.com",
userAgentHeader: "Mozilla/5.0"
)
Fetching Curated Recommendations
The getCuratedRecommendations()
method fetches recommendations based on the provided request parameters.
val request = CuratedRecommendationsRequest(
locale = Locale.EN_US,
region = "US",
count = 4,
topics = listOf("business"),
feeds = listOf("sections")
)
try {
val response: CuratedRecommendationsResponse = client.getCuratedRecommendations(request)
println("Received recommendations: $response")
} catch (e: CuratedRecommendationsError) {
println("Error fetching recommendations: ${e.message}")
}
let request = CuratedRecommendationsRequest(
locale: Locale.en-US,
region: "US",
count: 4,
topics: ["business"],
feeds: ["sections"]
)
do {
let response = try client.getCuratedRecommendations(request: request)
print("Received recommendations: \(response)")
} catch {
print("Error fetching recommendations: \(error)")
}
Data Models
Curated Recommendations Request Model
The CuratedRecommendationsRequest
model defines the parameters required to request curated recommendations.
Request Fields
Field |
Type |
Description |
---|---|---|
|
|
The Firefox installed locale, e.g., |
|
|
(Optional) The country-level region, e.g., |
|
|
(Optional) The maximum number of recommendations to return. Defaults to |
|
|
(Optional) A list of preferred curated topics. |
|
|
(Optional) A list of additional data feeds. Accepted values: |
|
|
(Optional) A list of section settings that the user follows or has blocked. |
|
|
(Optional) The Nimbus New Tab experiment name that the user is enrolled in. Used to run backend experiments independently of Firefox releases. |
|
|
(Optional) The branch name of the Nimbus experiment that the user is in. |
|
|
(Optional, defaults to |
Curated Recommendations Response Model
The CuratedRecommendationsResponse
model defines the response format containing recommendations.
Response Fields
Field |
Type |
Description |
---|---|---|
|
|
The timestamp (in milliseconds) indicating when the recommendations were generated. |
|
|
A list of curated recommendation items. |
|
|
(Optional) A structured set of multiple curated recommendation lists. |
|
|
(Optional) Returned if |
Error Handling
The Curated Recommendations component defines the following error hierarchy:
CuratedRecommendationsApiError
: Base errorNetwork(reason: string)
: Network error while making a request.Other(code: integer (optional), reason: string)
: Generic error containing an HTTP status code and message.
Handling Errors in Kotlin and Swift
fun fetchCuratedRecommendations() {
try {
val response = client.getCuratedRecommendations(request)
} catch (e: CuratedRecommendationsError.Network) {
// Log and retry after 5 minutes
Log.w("Network error when fetching Curated Recommendations: ${e.reason}")
scheduleRetry(300)
} catch (e: CuratedRecommendationsError.Other) {
when (e.code) {
400 -> Log.e("Bad Request: ${e.reason}")
422 -> Log.e("Validation Error: ${e.reason}")
in 500..599 -> Log.e("Server Error: ${e.reason}")
else -> Log.e("Unexpected Error: ${e.reason}")
}
}
}
func fetchCuratedRecommendations() {
do {
let response = try client.getCuratedRecommendations(request)
} catch CuratedRecommendationsError.Network(let reason) {
// Log and retry after 5 minutes
print("Network error when fetching Curated Recommendations: \(reason)")
scheduleRetry(seconds: 300)
} catch CuratedRecommendationsError.Other(let code, let reason) {
switch code {
case 400:
print("Bad Request: \(reason)")
case 422:
print("Validation Error: \(reason)")
case 500...599:
print("Server Error: \(reason)")
default:
print("Unexpected Error: \(reason)")
}
}
}