Migrate best bets to pinned results
Migrate Optimizely Search & Navigation best bets to Optimizely Graph pinned results, covers configuration differences, data mapping, API usage, and search query updates.
Early access previewThis content is an early access preview and may change before general availability. Use the thumbs up or down at the end of this article to share feedback and help shape the final release.
Best bets in Optimizely Search & Navigation and pinned results in Optimizely Graph let you promote specific content to the top of search results for defined search phrases. This ensures that users see important or authoritative content before other results.
This guide explains how to migrate existing best bets configurations from Optimizely Search & Navigation to Optimizely Graph pinned results, including API usage, data mapping, and query updates.
When to use pinned results
Use pinned results to:
- Promote branded or navigational searches. For example, directing users to an About us page for company-related queries.
- Highlight campaign or seasonal content for specific keywords
- Ensure critical support or contact information appears first in search results
- Guide users to official or compliant content for regulatory or policy-related searches
Key differences and migration impact
The following table summarizes the main differences between Search & Navigation best bets and Optimizely Graph pinned results and highlights required migration actions.
| Feature | Search & Navigation | Graph | Migration impact |
|---|---|---|---|
| Configuration | Admin UI | REST API only | Build an API-based integration (HMAC or Basic authentication required) |
| Architecture | Phrase-to-content mapping | Collection-based | Create collections, then add pinned items |
| Content reference | Integer ID | GUID | Query Graph to map ContentReference.ID to ContentReference.GuidValue |
| Supported content | Internal and external URLs | Internal content only | Migrate internal content; handle external URLs separately |
| Title and description | Custom or derived from content | Not supported | Use content fields in the application layer |
| Display styling | Configurable in UI | Not supported | Implement styling in the application layer |
| Language handling | Single item can apply to all languages | Separate item per language | Create one pinned item per language |
| Priority control | Implicit (insertion order) | Explicit priority field | Assign priorities sequentially (1 is highest) |
| Result limit | Unlimited | Maximum of 5 | Select the five most important results |
| Query syntax | .ApplyBestBets() | pinned parameter | Update all search queries |
| Locale handling | Automatic | Explicit | Always specify locale in queries |
| Status | Delete to remove | Active or inactive | Use status for temporary or seasonal items |
NoteBoth Optimizely Search & Navigation and Optimizely Graph support case-insensitive phrase matching.
Migration workflow
1. Retrieve best bets from Search & Navigation
Use the IBestBetRepository interface to retrieve existing best bets.
Prerequisites
EPiServer.Find.FrameworkEPiServer.Find.CmsOptimizely.ContentGraph.Core
using EPiServer.Find;
using EPiServer.Find.Framework.BestBets;
using EPiServer.Find.Cms;
var allBestBets = _bestBetRepository.List().ToList();
var internalBestBets = allBestBets
.Where(bb => bb.BestBetSelector is PageBestBetSelector)
.ToList();
NoteOptimizely Graph supports internal CMS content only. Best bets that reference external URLs cannot be migrated and must be handled separately.
2. Map content ID to Graph GUID
Optimizely Graph uses content GUIDs instead of integer content Id. Query Graph to retrieve GUID values for the content you plan to pin.
query GetContentIds($ids: [Int!]) {
Content(where: { ContentLink: { Id: { in: $ids } } }, limit: 100) {
items {
ContentLink {
Id
GuidValue
}
}
}
}Store the mapping between ContentReference.ID and ContentReference.GuidValue for later use.
3. Create a pinned results collection
Create a collection to group related pinned results.
Endpoint
POST https://cg.optimizely.com/api/pinned/collections
{
"title": "Migrated Best Bets",
"key": "migrated-best-bets",
"isActive": true
}Save the collection key for use in GraphQL queries.
4. Add pinned items to the collection
Add each migrated best bet as a pinned item.
Endpoint
POST https://cg.optimizely.com/api/pinned/collections/{id}/items
{
"phrases": "support",
"targetKey": "<content-guid>",
"language": "en",
"priority": 1
}5. Update application search queries
Replace Search & Navigation-based search queries with Graph queries that use the pinned parameter.
query SearchWithPinnedResults(
$term: String!
$collection: String!
$locale: [Locales!]
) {
Content(
where: { _fulltext: { contains: $term } }
pinned: { phrase: $term, collections: [$collection] }
locale: $locale
) {
items {
Name
Url
}
}
}
Pinned results appear first in the response, followed by regular search results.
Verification and testing
Verify collections and pinned items using the REST API or Swagger UI, then validate search behavior using GraphiQL.
Remove the pinned parameter to compare results with and without pinned content.
Verify via REST API
Use the Swagger UI or direct API calls to verify your migration
Get all collections
GET https://cg.optimizely.com/api/pinned/collections
// Requires HMAC or Basic AuthExample Response
[
{
"id": "collection-guid-here",
"title": "Migrated Best Bets",
"key": "migrated-best-bets",
"isActive": true
}
]Get items in a collection
GET https://cg.optimizely.com/api/pinned/collections/{id}/items
// Requires HMAC or Basic AuthExample Response
[
{
"id": "item-guid-here",
"phrases": "support",
"targetKey": "12345678-abcd-1234-abcd-1234567890ab",
"language": "en",
"priority": 1,
"isActive": true
}
]Swagger UI: https://cg.optimizely.com/app/swagger (interactive API testing)
Test via GraphQL
GraphiQL: https://cg.optimizely.com/app/graphiql?auth=YOUR_SINGLE_KEY
Test Query
query {
Content(
where: { _fulltext: { contains: "support" } }
pinned: {
phrase: "support"
collections: ["migrated-best-bets"] # Use collection key, not ID
# collections: ["water", "chemistry"] # Multiple collections supported
}
locale: en
) {
items { Name Url }
}
}Updated 13 days ago
