diff --git a/docs.json b/docs.json
index 2b6d27598..e16cb3d13 100644
--- a/docs.json
+++ b/docs.json
@@ -433,6 +433,13 @@
"guides/multitenancy_nodejs"
]
},
+ {
+ "group": "Relevancy",
+ "pages": [
+ "guides/relevancy/ordering_ranking_rules",
+ "guides/relevancy/interpreting_ranking_scores"
+ ]
+ },
{
"group": "Deployment",
"pages": [
diff --git a/guides/relevancy/interpreting_ranking_scores.mdx b/guides/relevancy/interpreting_ranking_scores.mdx
new file mode 100644
index 000000000..8aec35cc7
--- /dev/null
+++ b/guides/relevancy/interpreting_ranking_scores.mdx
@@ -0,0 +1,309 @@
+---
+title: Interpreting ranking score details
+description: Learn how to understand ranking score details to see how Meilisearch evaluates each result and which rules determined their order.
+---
+
+# How do I interpret ranking score details?
+
+[In the previous guide](/guides/relevancy/ordering_ranking_rules), we covered how ranking rules determine result order and how changing their sequence affects what your users see first. But when you're actually making those tweaks, how do you know if they're working the way you expect?
+
+That's where ranking score details come in. They give you a behind-the-scenes view of every ranking decision Meilisearch made for each result — with specific numeric scores for each relevancy rule, in the order they were evaluated.
+
+You'll be able to see things like: did Proximity decide this result's position, or was it Typo? Did Sort even get a chance to act, or did an earlier rule already settle things? And since Sort doesn't measure relevance (it shows a `value` rather than a `score`), the details also make it clear exactly where Sort slotted into the evaluation path and whether it actually influenced the final order.
+
+**Firstly, how do I see ranking score details?**
+
+When you search you can pass in an option to view the details of scoring and sorting using `“showRankingScoreDetails”: true` and it will return an indepth look at the ranking rules that you are working with
+
+```markdown
+curl \
+ -X POST 'MEILISEARCH_URL/indexes/movies/search' \
+ -H 'Content-Type: application/json' \
+ --data-binary '{
+ "q": "dragon",
+ "showRankingScoreDetails": true
+ }'
+```
+
+Ranking Score details example
+
+```markdown
+{
+ "hits": [
+ {
+ "id": 31072,
+ "title": "Dragon",
+ "overview": "In a desperate attempt to save her kingdom…",
+ …
+ "_rankingScoreDetails": {
+ "words": {
+ "order": 0,
+ "matchingWords": 4,
+ "maxMatchingWords": 4,
+ "score": 1.0
+ },
+ "typo": {
+ "order": 2,
+ "typoCount": 1,
+ "maxTypoCount": 4,
+ "score": 0.75
+ },
+ "name:asc": {
+ "order": 1,
+ "value": "Dragon"
+ }
+ }
+ },
+ …
+ ],
+ …
+}
+```
+
+# Ranking rules: same data, different results. How `sort` placement changes outcomes
+
+## The setup
+
+You run a **recipe search app**. You have two recipes in your index:
+
+```json
+[
+ {
+ "id": 1,
+ "title": "Easy Chicken Curry",
+ "description": "A quick and simple chicken curry ready in 20 minutes",
+ "prep_time_minutes": 20
+ },
+ {
+ "id": 2,
+ "title": "Chicken Stew with Curry Spices and Vegetables",
+ "description": "A hearty stew with warming spices",
+ "prep_time_minutes": 15
+ }
+]
+```
+
+A user searches for `"chicken curry"` and sorts by `prep_time_minutes:asc` (quickest first).
+
+Both documents match both search words. But **Doc 1** is clearly the stronger text match as `"chicken"` and `"curry"` appear right next to each other in the title. **Doc 2** has both words in the title too, but they're separated by several other words.
+
+Let's see how moving Sort **one position** in your ranking rules changes which result comes first, and how to read the ranking score details to understand why.
+
+---
+
+## Scenario A: `sort` placed AFTER Group 1 rules (recommended)
+
+We’ve set up our ranking rules to have sort after our Group 1 wide net rules.
+
+```json
+["words", "typo", "proximity", "sort", "attribute", "exactness"]
+```
+
+With this set up Meilisearch evaluates the text relevance rules first, *then* uses Sort.
+
+### 🥇 Result #1 — Easy Chicken Curry
+
+```json
+{
+ "prep_time_minutes": 20,
+ "title": "Easy Chicken Curry",
+ "id": 1,
+ "description": "A quick and simple chicken curry ready in 20 minutes",
+ "_rankingScore": 0.9982363315696648,
+ "_rankingScoreDetails": {
+ "words": {
+ "order": 0,
+ "matchingWords": 2,
+ "maxMatchingWords": 2,
+ "score": 1.0
+ },
+ "typo": { "order": 1, "typoCount": 0, "maxTypoCount": 2, "score": 1.0 },
+ "proximity": { "order": 2, "score": 1.0 },
+ "prep_time_minutes:asc": { "order": 3, "value": 20.0 },
+ "attribute": {
+ "order": 4,
+ "attributeRankingOrderScore": 1.0,
+ "queryWordDistanceScore": 0.9047619047619048,
+ "score": 0.9682539682539683
+ },
+ "exactness": {
+ "order": 5,
+ "matchType": "noExactMatch",
+ "matchingWords": 2,
+ "maxMatchingWords": 2,
+ "score": 0.3333333333333333
+ }
+ }
+ }
+```
+
+### 🥈 Result #2 — Chicken Stew with Curry Spices and Vegetables
+
+```json
+{
+ "prep_time_minutes": 15,
+ "title": "Chicken Stew with Curry Spices and Vegetables",
+ "id": 2,
+ "description": "A hearty stew with warming spices",
+ "_rankingScore": 0.9149029982363316,
+ "_rankingScoreDetails": {
+ "words": {
+ "order": 0,
+ "matchingWords": 2,
+ "maxMatchingWords": 2,
+ "score": 1.0
+ },
+ "typo": { "order": 1, "typoCount": 0, "maxTypoCount": 2, "score": 1.0 },
+ "proximity": { "order": 2, "score": 0.5 },
+ "prep_time_minutes:asc": { "order": 3, "value": 15.0 },
+ "attribute": {
+ "order": 4,
+ "attributeRankingOrderScore": 1.0,
+ "queryWordDistanceScore": 0.9047619047619048,
+ "score": 0.9682539682539683
+ },
+ "exactness": {
+ "order": 5,
+ "matchType": "noExactMatch",
+ "matchingWords": 2,
+ "maxMatchingWords": 2,
+ "score": 0.3333333333333333
+ }
+ }
+
+```
+
+### What decided this? Reading the score details
+
+Walk through the rules in `order` (0, 1, 2…) and look for where the scores diverge:
+
+| Step | Rule | Doc 1 | Doc 2 | Outcome |
+| --- | --- | --- | --- | --- |
+| 0 | **Words** | 2/2 → `1.0` | 2/2 → `1.0` | 🤝 Tie |
+| 1 | **Typo** | 0 typos → `1.0` | 0 typos → `1.0` | 🤝 Tie |
+| 2 | **Proximity** | `1.0` | `0.5` | ✅ **Doc 1 wins here** |
+
+Proximity broke the tie. `"chicken"` and `"curry"` sit right next to each other in Doc 1's title (score `1.0`), but are separated by three words in Doc 2's title (score `0.5`).
+
+Sort (order 3) never got a chance to act because Proximity already decided the winner. **Even though Doc 2 has a faster prep time (15 min vs 20 min), it ranks second because text relevance was evaluated first.**
+
+Also notice: Sort shows a `value` instead of a `score`. That's because Sort doesn't measure relevance, it just orders by the field value. This is why Sort doesn't contribute to `_rankingScore`.
+
+---
+
+## Scenario B: `sort` placed BEFORE Group 1 rules
+
+Now let's move `sort` to the top of our ranking rules:
+
+```json
+["sort", "words", "typo", "proximity", "attribute", "exactness"]
+```
+
+### 🥇 Result #1 — Chicken Stew with Curry Spices and Vegetables
+
+```json
+ {
+ "prep_time_minutes": 15,
+ "title": "Chicken Stew with Curry Spices and Vegetables",
+ "id": 2,
+ "description": "A hearty stew with warming spices",
+ "_rankingScore": 0.9149029982363316,
+ "_rankingScoreDetails": {
+ "prep_time_minutes:asc": { "order": 0, "value": 15.0 },
+ "words": {
+ "order": 1,
+ "matchingWords": 2,
+ "maxMatchingWords": 2,
+ "score": 1.0
+ },
+ "typo": { "order": 2, "typoCount": 0, "maxTypoCount": 2, "score": 1.0 },
+ "proximity": { "order": 3, "score": 0.5 },
+ "attribute": {
+ "order": 4,
+ "attributeRankingOrderScore": 1.0,
+ "queryWordDistanceScore": 0.9047619047619048,
+ "score": 0.9682539682539683
+ },
+ "exactness": {
+ "order": 5,
+ "matchType": "noExactMatch",
+ "matchingWords": 2,
+ "maxMatchingWords": 2,
+ "score": 0.3333333333333333
+ }
+ }
+ }
+```
+
+### 🥈 Result #2 — Easy Chicken Curry
+
+```json
+{
+ "prep_time_minutes": 20,
+ "title": "Easy Chicken Curry",
+ "id": 1,
+ "description": "A quick and simple chicken curry ready in 20 minutes",
+ "_rankingScore": 0.9982363315696648,
+ "_rankingScoreDetails": {
+ "prep_time_minutes:asc": { "order": 0, "value": 20.0 },
+ "words": {
+ "order": 1,
+ "matchingWords": 2,
+ "maxMatchingWords": 2,
+ "score": 1.0
+ },
+ "typo": { "order": 2, "typoCount": 0, "maxTypoCount": 2, "score": 1.0 },
+ "proximity": { "order": 3, "score": 1.0 },
+ "attribute": {
+ "order": 4,
+ "attributeRankingOrderScore": 1.0,
+ "queryWordDistanceScore": 0.9047619047619048,
+ "score": 0.9682539682539683
+ },
+ "exactness": {
+ "order": 5,
+ "matchType": "noExactMatch",
+ "matchingWords": 2,
+ "maxMatchingWords": 2,
+ "score": 0.3333333333333333
+ }
+ }
+ }
+```
+
+### Reading the score details - what changed?
+
+Look at the `order` values. Sort is now `order: 0` so it runs first.
+
+| Step | Rule | Doc 1 (Easy Chicken Curry) | Doc 2 (Chicken Stew…) | Outcome |
+| --- | --- | --- | --- | --- |
+| 0 | **Sort** (`prep_time_minutes:asc`) | value: `20` | value: `15` | ✅ **Doc 2 wins here** |
+
+Sort immediately separated the documents: 15 min beats 20 min. `:asc` will sort lowest to highest. Words, Typo, Proximity, and the rest never got a say.
+
+Notice something important: **Doc 1 still has a higher `_rankingScore` (0.998 vs 0.914)** but it ranks second. This is exactly what we described in [Ordering ranking rules](/guides/relevancy/ordering_ranking_rules): ranking score only measures text relevance. Sort affects the final order but doesn't change the ranking score. If you only looked at `_rankingScore`, you'd think Doc 1 should be first. The score details tell you the real story.
+
+---
+
+## Side by side
+In both scenarios the user searches for `"chicken curry"` and sorts by `prep_time_minutes:asc` (quickest first). The only change is the ranking rule placement.
+
+| | Scenario A (Sort is placed after Group 1 ranking rules) | Scenario B (Sort is placed first) |
+| --- | --- | --- |
+| **#1 result** | Easy Chicken Curry (20 min) | Chicken Stew with Curry… (15 min) |
+| **Decided by** | Proximity (order 2) | Sort (order 0) |
+| **Doc 1 `_rankingScore`** | 0.998 | 0.998 (same — sort doesn't affect it) |
+| **Doc 2 `_rankingScore`** | 0.914 | 0.914(same — sort doesn't affect it) |
+| **Best for** | Users who want the most relevant recipe | Users who want the quickest recipe regardless of match quality |
+
+---
+
+## The takeaway
+
+Moving Sort **one position** flipped the results. The ranking score details let you see exactly why:
+
+- **Look at the `order` values** to understand the sequence rules were applied
+- **Find where scores first diverge** — that's the rule that decided the final order
+- **Remember that Sort shows a `value`, not a `score`** It doesn't contribute to `_rankingScore`, which is why a higher-scored document can rank lower when Sort takes priority
+
+Start with Sort after Group 1 rules (Scenario A) and adjust from there based on what your users expect.
\ No newline at end of file
diff --git a/guides/relevancy/ordering_ranking_rules.mdx b/guides/relevancy/ordering_ranking_rules.mdx
new file mode 100644
index 000000000..53e9b6822
--- /dev/null
+++ b/guides/relevancy/ordering_ranking_rules.mdx
@@ -0,0 +1,122 @@
+---
+title: Ordering ranking rules
+description: Learn how Meilisearch orders search results and how to customize ranking rule order for your use case.
+---
+
+# Ranking rules: getting the order right for you
+
+**When to read this guide**
+
+This guide is for you if you want to understand how Meilisearch orders your search results and how to customize that behavior for your specific use case.
+
+You might be here because you've noticed a document with a lower ranking score appearing above one with a higher score, or you're curious about what happens when you adjust the ranking rule sequence. Maybe you're proactively exploring how to fine-tune results before going live, or you want to prioritize certain types of content over others.
+
+**What you'll learn:** This guide explains how Meilisearch's ranking rules system works behind the scenes - how ranking scores relate to final result order, and how to adjust rankings to match your needs. You'll get practical tips and recommendations for common scenarios, so you can confidently tune your search results.
+
+## **How Meilisearch ranks results**
+
+### **Ranking score vs. final order**
+
+**Ranking score only measures text match quality.** It doesn't include Sort or Custom ranking rules.
+
+Ever noticed a document with a lower ranking score appearing higher in results? That's normal. The ranking score captures text relevance, but your final result order also includes Sort and Custom ranking rules, which don’t care for textual relevancy, and so these don't contribute to the ranking score. Understanding how these two work together is important to tweak effectively.
+
+### **How ranking rules work**
+
+Meilisearch applies ranking rules sequentially. Each rule sorts documents into buckets and passes them to the next rule. This is why rule order matters - earlier rules take priority and later rules serve only as tie-breakers.
+
+### Types of ranking rules
+
+**Group 1 - Broad matching: Word, Type, Proximity (included in ranking score)**
+
+This covers things like:
+
+- **Word**: How many of your search terms appear in the document (more matches = higher ranking)
+- **Typo**: Whether these matches are the exact words or matches that are included through typo-tolerance (exact matches rank higher)
+- **Proximity**: How close together your search terms appear in the document (closer = more relevant)
+
+**These three rules cast a wide net and return lots of results.** That's good—you want to start broad and then narrow down, not the other way around. If you start too narrow you can lose relevancy easily.
+
+**Group 2 - Fine-tuning : Exactness, Attribute (included in ranking score)**
+
+This covers things like:
+
+- **Exactness**: Did the document match your whole search term or just pieces of it? Whole matches rank higher, especially when an entire field matches exactly or starts with your query. Documents containing extra content beyond the search term are ranked lower.
+- **Attribute**: Matches in your most important fields rank higher, and matches near the beginning of a field rank higher. You set field priority in `searchableAttributes`, with fields at the top of the list treated as the most important.
+
+**These are your fine-tuning filters.** They return fewer, more precise results. Use these after Group 1 rules to refine your large result set into something more precise.
+
+If you want to dive deeper into the [built in ranking rules](https://www.meilisearch.com/docs/learn/relevancy/ranking_rules) and [custom ranking rules](https://www.meilisearch.com/docs/learn/relevancy/custom_ranking_rules) we have more information available in our documentation.
+
+**And finally... Sort & Custom ranking rules (NOT included in ranking score)**
+
+Its important to note that `sort` ,`asc/desc` custom ranking rules will not be reflected in the Ranking Score. However if they are set, and how they are set, can affect your results. Heres what you need to know..
+
+**Sort**
+
+The Sort rule only activates when you use the `sort` parameter in your search query. **Without that parameter, it has no effect.**
+
+When you do use `sort`, whatever you specify as a sort gets swapped into the Sort position in your ranking rules:
+
+Search query:
+
+```json
+"q": "hello"
+"sort": [
+ "price:asc",
+ "author:desc"
+]
+```
+
+Ranking rules:
+
+```json
+[
+ "words",
+ "typo",
+ "proximity",
+ "attribute",
+ "sort", // "price:asc" "author:desc" gets swapped in here
+ "exactness",
+ "release_date:asc",
+ "movie_ranking:desc"
+]
+```
+
+**Key behaviour: Sort ignores text relevance**
+
+Sort and Custom ranking rules don't consider how well documents match your search query - they simply order results alphabetically or numerically by your chosen field (price, date, etc.).
+
+**Placement matters.** If you put Sort or Custom ranking rules at the top of your ranking rules, results will be ordered by that field instead of by text relevance. Apart from very specific use cases, such as price ordering, this usually creates a poor search experience where less relevant results appear first just because they have the right price or date.
+
+## Our Recommendations for Ranking Rule Ordering
+
+### Keep Group 1 rules first (Words, Typo, Proximity)
+
+Start with `words` as your first rule as it's the foundation. Every other rule depends on word matches existing, so it makes sense to establish those first. Follow it with `typo` and `proximity` to round out your broad matching.
+
+These three rules cast a wide net and pass a large pool of relevant results through the ranking chain. Starting broad is important. If you begin too narrow, you risk losing relevant documents before the later rules get a chance to refine them.
+
+### Place Sort strategically
+
+We recommend putting Sort after your Group 1 rules and before your Group 2 rules (Attribute, Exactness). This way, Meilisearch finds relevant results first and then uses your sort field to order documents that have similar text relevance, giving you a balance of match quality and sorting.
+
+If sorting matters more than text relevance for your use case - like an e-commerce price filter where users expect strict price ordering - move Sort higher. Just remember that Sort only activates when you include the `sort` parameter in your search query. Without it, the Sort rule has no effect.
+
+One thing to watch: placing Sort too late means most results are already in their final position before Sort gets a chance to act. If your sort field isn't influencing results the way you expect, try moving it up one position at a time and testing until you find the right spot. For a practical look at how this works, see [How Do I Interpret Ranking Score Details?](/guides/relevancy/interpreting_ranking_scores) where we show the same search returning different results just by moving Sort one position.
+
+### Use Custom ranking rules as tiebreakers
+
+Place custom ranking rules at the end of your sequence. They work best for adding business logic after text relevance has been established — things like popularity, recency, or user ratings. For example, if two recipes match equally well for "chicken curry," a custom `popularity:desc` rule can push the one with more saves to the top.
+
+### Going deeper
+
+Each ranking rule has its own settings you can fine-tune beyond just ordering. For example, you can adjust which fields take priority in attribute ranking, or configure how aggressively typo tolerance matches similar words. If you want to dig into the specifics:
+
+- [Built-in ranking rules](https://www.meilisearch.com/docs/learn/relevancy/ranking_rules#list-of-built-in-ranking-rules) — how each rule works and what it evaluates
+- [Attribute ranking order](https://www.meilisearch.com/docs/learn/relevancy/attribute_ranking_order) — controlling which fields matter most
+- [Typo tolerance settings](https://www.meilisearch.com/docs/learn/relevancy/typo_tolerance_settings) — adjusting how flexible matching behaves
+
+**Want to see these rules in action?** In our next guide, [How Do I Interpret Ranking Score Details?](/guides/relevancy/interpreting_ranking_scores), we walk through a real example showing exactly how Meilisearch evaluates each rule — and how moving Sort one position can flip your results.
+
+---
\ No newline at end of file
diff --git a/snippets/generated-code-samples/code_samples_tenant_token_guide_generate_sdk_1.mdx b/snippets/generated-code-samples/code_samples_tenant_token_guide_generate_sdk_1.mdx
new file mode 100644
index 000000000..0893aee47
--- /dev/null
+++ b/snippets/generated-code-samples/code_samples_tenant_token_guide_generate_sdk_1.mdx
@@ -0,0 +1,56 @@
+
+
+```javascript JS
+import { generateTenantToken } from 'meilisearch/token'
+
+const searchRules = {
+ patient_medical_records: {
+ filter: 'user_id = 1'
+ }
+}
+const apiKey = 'B5KdX2MY2jV6EXfUs6scSfmC...'
+const apiKeyUid = '85c3c2f9-bdd6-41f1-abd8-11fcf80e0f76'
+const expiresAt = new Date('2025-12-20') // optional
+
+const token = await generateTenantToken({ apiKey, apiKeyUid, searchRules, expiresAt })
+```
+
+```python Python
+uid = '85c3c2f9-bdd6-41f1-abd8-11fcf80e0f76';
+api_key = 'B5KdX2MY2jV6EXfUs6scSfmC...'
+expires_at = datetime(2025, 12, 20)
+search_rules = {
+ 'patient_medical_records': {
+ 'filter': 'user_id = 1'
+ }
+}
+token = client.generate_tenant_token(api_key_uid=uid, search_rules=search_rules, api_key=api_key, expires_at=expires_at)
+```
+
+```ruby Ruby
+uid = '85c3c2f9-bdd6-41f1-abd8-11fcf80e0f76'
+api_key = 'B5KdX2MY2jV6EXfUs6scSfmC...'
+expires_at = Time.new(2025, 12, 20).utc
+search_rules = {
+ 'patient_medical_records' => {
+ 'filter' => 'user_id = 1'
+ }
+}
+
+token = client.generate_tenant_token(uid, search_rules, api_key: api_key, expires_at: expires_at)
+```
+
+```go Go
+searchRules := map[string]interface{}{
+ "patient_medical_records": map[string]string{
+ "filter": "user_id = 1",
+ },
+}
+options := &meilisearch.TenantTokenOptions{
+ APIKey: "B5KdX2MY2jV6EXfUs6scSfmC...",
+ ExpiresAt: time.Date(2025, time.December, 20, 0, 0, 0, 0, time.UTC),
+}
+
+token, err := client.GenerateTenantToken(searchRules, options);
+```
+
\ No newline at end of file
diff --git a/snippets/generated-code-samples/code_samples_tenant_token_guide_search_sdk_1.mdx b/snippets/generated-code-samples/code_samples_tenant_token_guide_search_sdk_1.mdx
new file mode 100644
index 000000000..ca8ed4a7a
--- /dev/null
+++ b/snippets/generated-code-samples/code_samples_tenant_token_guide_search_sdk_1.mdx
@@ -0,0 +1,23 @@
+
+
+```javascript JS
+const frontEndClient = new MeiliSearch({ host: 'http://localhost:7700', apiKey: token })
+frontEndClient.index('patient_medical_records').search('blood test')
+```
+
+```python Python
+front_end_client = Client('http://localhost:7700', token)
+front_end_client.index('patient_medical_records').search('blood test')
+```
+
+```ruby Ruby
+front_end_client = MeiliSearch::Client.new('http://localhost:7700', token)
+
+front_end_client.index('patient_medical_records').search('blood test')
+```
+
+```go Go
+client := meilisearch.New("http://localhost:7700", meilisearch.WithAPIKey("masterKey"))
+client.Index("patient_medical_records").Search("blood test", &meilisearch.SearchRequest{});
+```
+
\ No newline at end of file