> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usesatori.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# User Preferences

> Store and retrieve user preferences with memory

## Overview

This example shows how to use Satori to store and retrieve user preferences, enabling personalized experiences across your application.

## Use Case

Build an AI assistant that remembers user preferences for:

* UI settings (theme, language, layout)
* Content preferences (topics, formats, difficulty)
* Communication style (formal vs casual, verbosity)
* Notification preferences

## Implementation

### Saving Preferences

```typescript app/api/preferences/route.ts theme={null}
import { MemoryClient } from '@usesatori/tools';
import { auth } from '@clerk/nextjs/server';

export async function POST(req: Request) {
  const { userId } = await auth();
  
  if (!userId) {
    return new Response('Unauthorized', { status: 401 });
  }
  
  const { preference, category } = await req.json();
  
  const client = new MemoryClient({
    apiKey: process.env.SATORI_API_KEY!,
    baseUrl: process.env.SATORI_URL!,
    userId,
  });
  
  // Save preference with metadata
  await client.addMemory(preference, {
    metadata: {
      type: 'preference',
      category,
      timestamp: new Date().toISOString(),
    },
  });
  
  return Response.json({ success: true });
}
```

### Retrieving Preferences

```typescript app/api/preferences/get/route.ts theme={null}
import { MemoryClient } from '@usesatori/tools';
import { auth } from '@clerk/nextjs/server';

export async function GET(req: Request) {
  const { userId } = await auth();
  
  if (!userId) {
    return new Response('Unauthorized', { status: 401 });
  }
  
  const { searchParams } = new URL(req.url);
  const category = searchParams.get('category');
  
  const client = new MemoryClient({
    apiKey: process.env.SATORI_API_KEY!,
    baseUrl: process.env.SATORI_URL!,
    userId,
  });
  
  // Search for preferences in a specific category
  const query = category 
    ? `${category} preferences`
    : 'user preferences';
    
  const preferences = await client.searchMemories(query, {
    limit: 20,
    threshold: 0.7,
  });
  
  // Filter by metadata if needed
  const filtered = category
    ? preferences.filter(p => p.metadata?.category === category)
    : preferences;
  
  return Response.json({ preferences: filtered });
}
```

### Preferences UI Component

```typescript components/PreferencesPanel.tsx theme={null}
'use client';

import { useState, useEffect } from 'react';

interface Preference {
  id: string;
  content: string;
  category: string;
  createdAt: string;
}

export function PreferencesPanel() {
  const [preferences, setPreferences] = useState<Preference[]>([]);
  const [newPref, setNewPref] = useState('');
  const [category, setCategory] = useState('general');

  useEffect(() => {
    loadPreferences();
  }, []);

  async function loadPreferences() {
    const response = await fetch('/api/preferences/get');
    const data = await response.json();
    setPreferences(data.preferences);
  }

  async function savePreference() {
    await fetch('/api/preferences', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        preference: newPref,
        category,
      }),
    });
    
    setNewPref('');
    loadPreferences();
  }

  return (
    <div className="p-6 max-w-2xl mx-auto">
      <h2 className="text-2xl font-bold mb-6">Your Preferences</h2>
      
      {/* Add Preference */}
      <div className="mb-6 p-4 bg-gray-50 rounded-lg">
        <h3 className="font-semibold mb-3">Add New Preference</h3>
        <div className="space-y-3">
          <select
            value={category}
            onChange={(e) => setCategory(e.target.value)}
            className="w-full p-2 border rounded"
          >
            <option value="general">General</option>
            <option value="ui">UI/Theme</option>
            <option value="content">Content</option>
            <option value="communication">Communication</option>
            <option value="notifications">Notifications</option>
          </select>
          
          <input
            value={newPref}
            onChange={(e) => setNewPref(e.target.value)}
            placeholder="e.g., I prefer dark mode"
            className="w-full p-2 border rounded"
          />
          
          <button
            onClick={savePreference}
            disabled={!newPref.trim()}
            className="w-full px-4 py-2 bg-purple-600 text-white rounded hover:bg-purple-700 disabled:opacity-50"
          >
            Save Preference
          </button>
        </div>
      </div>
      
      {/* Preferences List */}
      <div className="space-y-3">
        <h3 className="font-semibold">Saved Preferences</h3>
        {preferences.length === 0 ? (
          <p className="text-gray-500">No preferences saved yet</p>
        ) : (
          preferences.map((pref) => (
            <div
              key={pref.id}
              className="p-3 bg-white border rounded-lg"
            >
              <p className="text-sm font-medium text-purple-600 mb-1">
                {pref.category}
              </p>
              <p>{pref.content}</p>
              <p className="text-xs text-gray-500 mt-1">
                {new Date(pref.createdAt).toLocaleDateString()}
              </p>
            </div>
          ))
        )}
      </div>
    </div>
  );
}
```

## Preference Categories

### UI Preferences

```typescript theme={null}
// Theme preference
await client.addMemory('User prefers dark mode', {
  metadata: { category: 'ui', subcategory: 'theme' },
});

// Layout preference
await client.addMemory('User prefers compact layout with sidebar', {
  metadata: { category: 'ui', subcategory: 'layout' },
});

// Language preference
await client.addMemory('User prefers Spanish language', {
  metadata: { category: 'ui', subcategory: 'language' },
});
```

### Content Preferences

```typescript theme={null}
// Topic interests
await client.addMemory('User is interested in AI and machine learning', {
  metadata: { category: 'content', subcategory: 'topics' },
});

// Content format
await client.addMemory('User prefers video tutorials over text articles', {
  metadata: { category: 'content', subcategory: 'format' },
});

// Difficulty level
await client.addMemory('User prefers advanced technical content', {
  metadata: { category: 'content', subcategory: 'difficulty' },
});
```

### Communication Preferences

```typescript theme={null}
// Tone preference
await client.addMemory('User prefers casual, friendly communication', {
  metadata: { category: 'communication', subcategory: 'tone' },
});

// Verbosity
await client.addMemory('User prefers concise responses', {
  metadata: { category: 'communication', subcategory: 'verbosity' },
});

// Explanation style
await client.addMemory('User likes code examples with explanations', {
  metadata: { category: 'communication', subcategory: 'style' },
});
```

## Using Preferences in Chat

```typescript app/api/chat/route.ts theme={null}
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { MemoryClient } from '@usesatori/tools';

export async function POST(req: Request) {
  const { userId } = await auth();
  const { messages } = await req.json();
  
  const client = new MemoryClient({
    apiKey: process.env.SATORI_API_KEY!,
    baseUrl: process.env.SATORI_URL!,
    userId: userId!,
  });
  
  // Fetch user preferences
  const preferences = await client.searchMemories('user preferences', {
    limit: 10,
  });
  
  // Build preferences context
  const preferencesContext = preferences
    .map(p => p.content)
    .join('\n');
  
  const result = await streamText({
    model: openai('gpt-4o'),
    system: `You are a helpful assistant. Adapt your responses based on these user preferences:

${preferencesContext}

Follow these preferences in your communication style, content recommendations, and overall interaction.`,
    messages,
  });
  
  return result.toDataStreamResponse();
}
```

## Example Interactions

<AccordionGroup>
  <Accordion title="Setting UI preferences">
    **User:** "I prefer dark mode and a compact layout"

    **Assistant:** "Got it! I'll remember that you prefer dark mode and a compact layout. Your interface should reflect these preferences."

    *Saves: "User prefers dark mode" and "User prefers compact layout"*
  </Accordion>

  <Accordion title="Content recommendations">
    **User:** "Show me some tutorials"

    **Assistant:** "Based on your preferences for advanced technical content in video format, here are some great video tutorials on AI and machine learning..."

    *Uses preferences to personalize recommendations*
  </Accordion>

  <Accordion title="Communication adaptation">
    **User:** "Explain how embeddings work"

    **Assistant:** "Sure! Here's a concise explanation with code:

    ```python theme={null}
    # Embeddings convert text to vectors
    embedding = model.encode('Hello world')
    # Result: [0.23, -0.45, 0.67, ...]
    ```

    Embeddings capture semantic meaning in numbers that computers can compare."

    *Adapts to preference for concise responses with code examples*
  </Accordion>
</AccordionGroup>

## Advanced Patterns

### Preference Conflicts

```typescript theme={null}
// Handle conflicting preferences
const preferences = await client.searchMemories('theme preference');

// If multiple theme preferences exist, use the most recent
const sortedByDate = preferences.sort((a, b) => 
  new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
);

const currentTheme = sortedByDate[0];
```

### Preference Hierarchy

```typescript theme={null}
// Define preference importance
await client.addMemory('User strongly prefers TypeScript', {
  metadata: {
    category: 'content',
    importance: 'high',
    strength: 'strong',
  },
});

await client.addMemory('User somewhat likes Python', {
  metadata: {
    category: 'content',
    importance: 'medium',
    strength: 'moderate',
  },
});
```

### Preference Expiration

```typescript theme={null}
// Add expiration to temporary preferences
await client.addMemory('User is currently learning React', {
  metadata: {
    category: 'content',
    temporary: true,
    expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString(),
  },
});

// Clean up expired preferences
const allPrefs = await client.getAllMemories();
const now = Date.now();

for (const pref of allPrefs) {
  if (pref.metadata?.expiresAt) {
    const expiresAt = new Date(pref.metadata.expiresAt).getTime();
    if (now > expiresAt) {
      await client.deleteMemory(pref.id);
    }
  }
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Use clear, specific preference statements">
    ```typescript theme={null}
    // ✅ Good: Specific and actionable
    "User prefers dark mode with high contrast"
    "User wants email notifications only for critical alerts"

    // ❌ Bad: Vague
    "User likes dark stuff"
    "User doesn't want spam"
    ```
  </Accordion>

  <Accordion title="Organize with metadata">
    ```typescript theme={null}
    await client.addMemory('User prefers TypeScript', {
      metadata: {
        category: 'programming',
        subcategory: 'languages',
        importance: 'high',
        source: 'explicit', // vs 'inferred'
        confidence: 0.95,
      },
    });
    ```
  </Accordion>

  <Accordion title="Allow preference updates">
    ```typescript theme={null}
    // Search for existing preference
    const existing = await client.searchMemories('theme preference', {
      threshold: 0.9,
    });

    // Delete old preference
    if (existing.length > 0) {
      await client.deleteMemory(existing[0].id);
    }

    // Add new preference
    await client.addMemory('User now prefers light mode');
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Chat Example" icon="comments" href="/examples/chat-with-memory">
    See memory in conversations
  </Card>

  <Card title="Direct Client" icon="wrench" href="/guides/direct-client">
    Learn the MemoryClient API
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/memory/search">
    Explore search options
  </Card>

  <Card title="Metadata Guide" icon="tags" href="/concepts/how-it-works">
    Learn about metadata
  </Card>
</CardGroup>
