> ## Documentation Index
> Fetch the complete documentation index at: https://social-b97141fb-auto-generate-llmstxt.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Visitor Mode

> Enable visitor mode to allow anonymous users to browse public content without signing in. Server-side read-only controls protect platform integrity.

Visitor mode lets anonymous users browse public content read-only, without signing in. Access is controlled server-side to protect platform integrity.

<Warning>
  **Visitor mode is not enabled by default.** To enable visitor mode for your network, please contact [support@social.plus](mailto:support@social.plus) with your network details.
</Warning>

## Overview & Concepts

### What is Visitor Mode?

Visitor mode enables **anonymous public access** to your community, allowing users to browse and discover content without requiring authentication. This feature is ideal for growth funnels, SEO optimization, and public content discovery while maintaining platform security and stability.

<CardGroup cols={2}>
  <Card title="Visitor Users" icon="eye">
    **Purpose**: Anonymous users who browse public content\
    **Access**: Read-only permissions enforced server-side\
    **Tracking**: Identified by an SDK-generated device ID\
    **Use Case**: Public content discovery, growth funnel
  </Card>

  <Card title="Bot Users" icon="robot">
    **Purpose**: Search engine crawlers and automated indexers\
    **Access**: Read-only permissions for content indexing\
    **Tracking**: Identified by User-Agent analysis\
    **Use Case**: SEO optimization, content discoverability
  </Card>
</CardGroup>

### How Visitor Mode Works

Visitor mode uses an **SDK-generated device ID** to identify anonymous users while maintaining privacy:

<Steps>
  <Step title="Device Identification">
    The SDK generates or retrieves a stable device ID for the anonymous user
  </Step>

  <Step title="Visitor Login">
    The SDK logs in the user as a visitor using the device ID, with optional secure mode via authSignature
  </Step>

  <Step title="Server-Side Role Assignment">
    social.plus server assigns the "Visitor" or "Bot" role based on the request (User-Agent for bots)
  </Step>

  <Step title="Read-Only Access">
    Server-side permissions enforce read-only access, allowing content discovery without modification capabilities
  </Step>
</Steps>

```mermaid theme={null}
sequenceDiagram
    participant Device as User Device
    participant App as Your App
    participant SDK as social.plus SDK
    participant API as social.plus API

    Device->>App: Access public content
    App->>SDK: getVisitorDeviceId()
    SDK->>SDK: Generate/Retrieve Device ID
    SDK->>App: Return Device ID
    App->>SDK: loginAsVisitor(deviceId)
    SDK->>API: POST /api/v5/sessions/visitor
    API->>API: Assign "Visitor" Role
    API->>SDK: Return Session (Read-Only)
    SDK->>App: Login Complete
    App->>Device: Show Public Content
```

<Info>
  **Why device IDs?** This approach lets social.plus distinguish anonymous visitor sessions without requiring a signed-in user account. Visitors are restricted to read-only access, protecting community integrity.
</Info>

### User Type Comparison

Understanding the different user types helps you design the right access patterns:

<Tabs>
  <Tab title="Signed-In Users">
    <CodeGroup>
      ```typescript theme={null}
      // Full authenticated user with read/write access
      import { Client } from '@amityco/ts-sdk';

      const client = Client.createClient('your-api-key', 'sg');

      // ... your app setup code

      await Client.login({
        userId: 'user-123',
        displayName: 'John Doe',
      }, sessionHandler);
      ```
    </CodeGroup>

    **Capabilities:**

    * ✅ Full read/write access to all features
    * ✅ Real-time event connections (MQTT)
    * ✅ Push notifications
    * ✅ Create posts, comments, reactions
    * ✅ Join communities and follow users
  </Tab>

  <Tab title="Visitor Users">
    <CodeGroup>
      ```typescript theme={null}
      // Anonymous visitor with read-only access
      import { Client } from '@amityco/ts-sdk';

      const client = Client.createClient('your-api-key', 'sg');

      await Client.loginAsVisitor({
          sessionHandler,
      });
      ```
    </CodeGroup>

    **Capabilities:**

    * ✅ View public posts and content
    * ✅ Browse public communities
    * ✅ View user profiles
    * ❌ No real-time connections (no MQTT)
    * ❌ No push notifications
    * ❌ Cannot create content or interact
    * ❌ Cannot join communities or follow users
  </Tab>

  <Tab title="Bot Users">
    <CodeGroup>
      ```typescript theme={null}
      // Search engine crawler with read-only access
      import { Client } from '@amityco/ts-sdk';

      const client = Client.createClient('your-api-key', 'sg');

      await Client.loginAsBot({ sessionHandler });
      ```
    </CodeGroup>

    **Capabilities:**

    * ✅ Index public content for SEO
    * ✅ View public posts and communities
    * ✅ Separated analytics tracking
    * ❌ No real-time connections
    * ❌ No push notifications
    * ❌ No write operations
  </Tab>
</Tabs>

## Parameters

| Operation             | Parameter                | Required    | Platforms                | Description                                                                     |
| --------------------- | ------------------------ | ----------- | ------------------------ | ------------------------------------------------------------------------------- |
| Initialize SDK        | API key                  | Yes         | iOS, Android, TypeScript | Application API key from the social.plus Console.                               |
| Initialize SDK        | Region / endpoint        | Yes         | iOS, Android, TypeScript | Region where your social.plus application was created.                          |
| Get visitor device ID | None                     | No          | iOS, Android, TypeScript | SDK returns or generates the stable anonymous device ID.                        |
| Login as visitor      | `sessionHandler`         | Recommended | iOS, Android, TypeScript | Token-renewal handler for visitor sessions.                                     |
| Secure visitor login  | `authSignature`          | Secure mode | iOS, Android, TypeScript | Backend-generated HMAC signature for the visitor device ID and expiration time. |
| Secure visitor login  | `authSignatureExpiresAt` | Secure mode | iOS, Android, TypeScript | Expiration timestamp that was included in the signature.                        |
| Login as bot          | `sessionHandler`         | Recommended | TypeScript               | Token-renewal handler for explicit bot sessions.                                |
| Check user type       | None                     | No          | iOS, Android, TypeScript | SDK returns the current user type so the UI can adjust capabilities.            |

## Quick Start (Visitor Mode)

### Step 1: Initialize the SDK

Start by setting up the social.plus client with your API key:

<CodeGroup>
  ```swift iOS theme={null}
  let client = try! AmityClient(apiKey: "your-api-key", region: .SG)
  ```

  ```kotlin Android theme={null}
  AmityCoreClient.setup(
      apiKey = "your-api-key",
      endpoint = AmityEndpoint.SG
  )
  ```

  ```typescript TypeScript theme={null}
  import { Client } from '@amityco/ts-sdk';

  const client = Client.createClient('your-api-key', 'sg');
  ```
</CodeGroup>

### Step 2: Get Visitor Device ID

Generate or retrieve a unique device identifier for the visitor:

<CodeGroup>
  ```swift iOS theme={null}
  let deviceId = client.getVisitorDeviceId()
  print("Device ID: \(deviceId)")
  ```

  ```kotlin Android theme={null}
  val deviceId = AmityCoreClient.getVisitorDeviceId()
  Log.d("Visitor", "Device ID: $deviceId")
  ```

  ```typescript TypeScript theme={null}

  const client = Client.createClient('your-api-key', 'sg');
  const deviceId = await client.getVisitorDeviceId();

  console.log('Device ID:', deviceId);
  ```
</CodeGroup>

<Note>
  The device ID is automatically generated and cached on first access. This unique identifier is used to track the visitor session.
</Note>

### Step 3: Login as Visitor

Authenticate as an anonymous visitor to access public content:

<CodeGroup>
  ```swift iOS theme={null}
  Task { @MainActor in
      do {
          // Simple visitor login (development)
          try await client.loginAsVisitor(
              authSignature: nil,
              authSignatureExpiresAt: nil,
              sessionHandler: sessionHandler
          )
          print("Visitor login successful")
      } catch {
          print("Visitor login failed: \(error)")
      }
  }
  ```

  ```kotlin Android theme={null}
  // Simple visitor login (development)
  AmityCoreClient.loginAsVisitor(sessionHandler)
      .build()
      .submit()
      .doOnComplete {
          // Visitor login successful
      }
      .doOnError { error ->
          // Visitor login failed
      }
      .subscribe()
  ```

  ```typescript TypeScript theme={null}
  try {
      // Simple visitor login (development)
      await Client.loginAsVisitor({ sessionHandler });
      console.log('Visitor login successful');
  } catch (error) {
      console.error('Visitor login failed:', error);
  }
  ```
</CodeGroup>

### Step 4: Login as Bot (TypeScript Only)

For search engine crawlers and automated indexers:

<CodeGroup>
  ```typescript TypeScript theme={null}
  try {
      await Client.loginAsBot({ sessionHandler });
      console.log('Bot login successful');
  } catch (error) {
      console.error('Bot login failed:', error);
  }
  ```
</CodeGroup>

<Info>
  Bot login is automatically determined by User-Agent analysis on the server. Use this method when you need explicit bot role assignment.
</Info>

### Step 5: Check User Type

Verify the current user type to adapt your UI accordingly:

<CodeGroup>
  ```swift iOS theme={null}
  let userType = client.currentUserType
  switch userType {
  case .signedIn:
      print("User is authenticated")
  case .visitor:
      print("User is a visitor")
  case .bot:
      print("User is a bot")
  }
  ```

  ```kotlin Android theme={null}
  val userType = AmityCoreClient.getCurrentUserType()
  when (userType) {
      AmityUserType.SIGNED_IN -> Log.d("Auth", "User is authenticated")
      AmityUserType.VISITOR -> Log.d("Auth", "User is a visitor")
      AmityUserType.BOT -> Log.d("Auth", "User is a bot")
  }
  ```

  ```typescript TypeScript theme={null}
  import { Client, UserTypeEnum } from '@amityco/ts-sdk';

  const userType = Client.getCurrentUserType();
  switch (userType) {
      case UserTypeEnum.SIGNED_IN:
          console.log('User is authenticated');
          break;
      case UserTypeEnum.VISITOR:
          console.log('User is a visitor');
          break;
      case UserTypeEnum.BOT:
          console.log('User is a bot');
          break;
  }
  ```
</CodeGroup>

### Step 6: Logout

End the visitor session:

<CodeGroup>
  ```swift iOS theme={null}
  do {
      try await client.secureLogout()
  } catch {
      /// Handle error from revoking accessToken here
  }
  ```

  ```kotlin Android theme={null}
  AmityCoreClient.secureLogout()
      .doOnComplete {
          // Void
      }
      .doOnError {
          // Exception
      }
      .subscribe()
  ```

  ```typescript TypeScript theme={null}
  const handleSecureLogout = async () => {
    await Client.secureLogout();
  };

  handleSecureLogout();
  ```
</CodeGroup>

## Secure Visitor Mode (Production)

For production environments, secure visitor mode adds an extra layer of authentication by requiring cryptographic signatures for visitor sessions. Once secure mode is enabled, all visitor login requests must include a valid auth signature generated by your backend server.

<Warning>
  **Secure visitor mode is not enabled by default.** Even if visitor mode is enabled, secure mode must be enabled separately. Contact [support@social.plus](mailto:support@social.plus) to enable secure visitor mode for your network.
</Warning>

### Getting Your Visitor Secret

After visitor secure mode is enabled for your network, retrieve your visitor application secret from the Console:

<Steps>
  <Step title="Navigate to Settings">
    Open your social.plus Console and go to **Settings** → **Integrations**
  </Step>

  <Step title="Locate Visitor Secret">
    Scroll to the **Visitor Secure Mode Setup** section (visible only after visitor secure mode is enabled)
  </Step>

  <Step title="Copy Secret">
    Create new secret and store it securely in your backend environment variables
  </Step>
</Steps>

<Warning>
  **Security Best Practice:** Never expose your **secret** in client-side code, mobile apps, or version control. This secret must remain on your backend server only.
</Warning>

### Backend Auth Signature Generation

Your backend server must generate time-limited auth signatures using HMAC-SHA256 encryption:

<CodeGroup>
  ```javascript theme={null}
  // Complete Express.js backend example
  const express = require('express');
  const crypto = require('crypto');
  require('dotenv').config();

  const app = express();
  const PORT = process.env.PORT || 3000;

  // Middleware to parse JSON request bodies
  app.use(express.json());

  // Visitor auth signature endpoint
  app.post('/api/visitor/auth-signature', async (req, res) => {
    try {
      const { deviceId } = req.body;

      // Set expiration (e.g., 1 hour from now)
      const authSignatureExpiresAt = new Date(Date.now() + 3600000).toISOString();

      // Create signature using HMAC-SHA256 with your visitor secret
      const message = `deviceId=${deviceId}&authSignatureExpiresAt=${authSignatureExpiresAt}`;
      const authSignature = crypto
        .createHmac('sha256', process.env.SOCIAL_PLUS_VISITOR_APP_SECRET)
        .update(message)
        .digest('hex');

      res.json({
        authSignature,
        authSignatureExpiresAt
      });
    } catch (error) {
      console.error('Error generating auth signature:', error);
      res.status(500).json({ error: 'Failed to generate auth signature' });
    }
  });

  // Start server
  app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
  });
  ```
</CodeGroup>

**Setup Instructions:**

1. Install dependencies:

```bash theme={null}
npm install express dotenv
```

2. Create a `.env` file in your project root:

```env theme={null}
SOCIAL_PLUS_VISITOR_APP_SECRET=your_visitor_secret_from_console
PORT=3000
```

3. Run the server:

```bash theme={null}
node server.js
```

<Note>
  **How It Works:** The signature is created by hashing the device ID and expiration timestamp with your secret key. social.plus servers verify the signature using the same secret, ensuring the request originated from your trusted backend.
</Note>

### Secure Visitor Login

Use auth signatures for production visitor sessions. Obtain `authSignature` via the API implemented in the previous step, and provide the corresponding values to the `loginAsVisitor()` function.

<CodeGroup>
  ```swift iOS theme={null}
  Task { @MainActor in
      do {
          // Get device ID
          let deviceId = client.getVisitorDeviceId()

          // Request auth signature from your backend
          let (signature, expiresAt) = try await fetchAuthSignature(deviceId: deviceId)

          // Login with secure mode
          try await client.loginAsVisitor(
              authSignature: signature,
              authSignatureExpiresAt: expiresAt,
              sessionHandler: sessionHandler
          )
          print("Secure visitor login successful")
      } catch {
          print("Secure visitor login failed: \(error)")
      }
  }
  ```

  ```kotlin Android theme={null}
  val deviceId = AmityCoreClient.getVisitorDeviceId()

  // Request auth signature from your backend
  fetchAuthSignature(deviceId) { signature, expiresAt ->
      AmityCoreClient.loginAsVisitor(sessionHandler)
          .authSignature(signature)
          .authSignatureExpiresAt(expiresAt)
          .build()
          .submit()
          .doOnComplete {
              // Secure visitor login successful
          }
          .doOnError { error ->
              // Secure visitor login failed
          }
          .subscribe()
  }
  ```

  ```typescript TypeScript theme={null}
  try {
      const deviceId = await client.getVisitorDeviceId();

      // Request auth signature from your backend
      const { authSignature, authSignatureExpiresAt } =
          await fetchAuthSignature(deviceId);

      // Login with secure mode
      await Client.loginAsVisitor({
          authSignature,
          authSignatureExpiresAt,
          sessionHandler,
      });
      console.log('Secure visitor login successful');
  } catch (error) {
      console.error('Secure visitor login failed:', error);
  }
  ```
</CodeGroup>

### Session Handler for Token Renewal

Implement session handlers to automatically refresh auth signatures:

<Tabs>
  <Tab title="iOS">
    <CodeGroup>
      ```swift theme={null}
      class VisitorSessionHandler: SessionHandler {
          func sessionWillRenewAccessToken(renewal: AccessTokenRenewal) {
              let deviceId = client.getVisitorDeviceId()

              Task {
                  do {
                      // Fetch new auth signature from your backend
                      let (signature, expiresAt) = try await fetchAuthSignature(deviceId: deviceId)
                      renewal.renewWithAuthSignature(
                          authSignature: signature,
                          authSignatureExpiresAt: expiresAt
                      )
                  } catch {
                      print("Failed to refresh visitor token: \(error)")
                      renewal.unableToRetrieveAuthSignature()
                  }
              }
          }
      }

      // Use during visitor login
      let sessionHandler = VisitorSessionHandler()
      try await client.loginAsVisitor(
          authSignature: signature,
          authSignatureExpiresAt: expiresAt,
          sessionHandler: sessionHandler
      )
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Android">
    <CodeGroup>
      ```kotlin theme={null}
      class VisitorSessionHandler : SessionHandler {
          override fun sessionWillRenewAccessToken(renewal: AccessTokenRenewal) {
              val deviceId = AmityCoreClient.getVisitorDeviceId()

              // Fetch new auth signature from your backend
              authRepository.fetchVisitorAuthSignature(deviceId) { authData ->
                  if (authData != null) {
                      renewal.renewWithAuthSignature(
                          authData.signature,
                          authData.expiresAt
                      )
                  } else {
                      renewal.unableToRetrieveAuthToken()
                  }
              }
          }
      }

      // Use during visitor login
      val sessionHandler = VisitorSessionHandler()
      AmityCoreClient.loginAsVisitor(sessionHandler)
          .authSignature(signature)
          .authSignatureExpiresAt(expiresAt)
          .build()
          .submit()
      ```
    </CodeGroup>
  </Tab>

  <Tab title="TypeScript">
    <CodeGroup>
      ```typescript theme={null}
      const createVisitorSessionHandler = (): Amity.SessionHandler => ({
          sessionWillRenewAccessToken: async (renewal: Amity.AccessTokenRenewal) => {
              try {
                  const deviceId = await client.getVisitorDeviceId();

                  // Fetch new auth signature from your backend
                  const { authSignature, authSignatureExpiresAt } =
                      await AuthService.fetchVisitorAuthSignature(deviceId);

                  renewal.renewWithAuthSignature({ authSignature, authSignatureExpiresAt });
              } catch (error) {
                  console.error('Failed to refresh visitor token:', error);
                  renewal.unableToRetrieveAuthSignature();
              }
          }
      });

      // Use during visitor login
      await Client.loginAsVisitor({
          authSignature,
          authSignatureExpiresAt,
          sessionHandler: createVisitorSessionHandler(),
      });
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Understanding Visitor Permissions

Visitor and bot users have **server-side enforced read-only permissions** to protect community integrity:

<CardGroup cols={2}>
  <Card title="Allowed Actions ✅" icon="check">
    * View public posts and content
    * Browse public communities
    * View user profiles
    * View comments and replies
    * View post reactions
    * Access public media (images, videos)
  </Card>

  <Card title="Restricted Actions ❌" icon="ban">
    * Create posts or stories
    * Comment or reply
    * React to posts/comments
    * Join communities
    * Follow/unfollow users
    * Report content or users
    * Send messages
    * Receive push notifications
    * Real-time event connections (MQTT)
  </Card>
</CardGroup>

### Permission Enforcement

All visitor restrictions are enforced **server-side** - attempting restricted actions will result in permission errors:

<CodeGroup>
  ```typescript Error Codes theme={null}
  // TypeScript and Android server error codes for visitor/bot permission denial
  ServerError.VISITOR_PERMISSION_DENIED: 403999
  ServerError.BOT_PERMISSION_DENIED: 403998
  ```

  ```typescript Example Error Handling theme={null}
  try {
      await createPost({ text: 'Hello world' });
  } catch (error) {
      if (String(error).includes('403999')) {
          // Show visitor upgrade prompt
          showVisitorWarning('Create an account or sign in to post');
      }
  }
  ```
</CodeGroup>

### Resource Conservation

Visitors and bots are excluded from resource-intensive features:

<Tabs>
  <Tab title="Real-Time Events">
    **MQTT Connection**: Disabled for visitors/bots

    * No real-time event subscriptions
    * No live updates or notifications
    * Reduces server load and connection costs
    * Does not count towards CCU (Concurrent Connection Users) limits

    <CodeGroup>
      ```typescript theme={null}
      // SDK automatically skips MQTT connection for visitors
      const userType = Client.getCurrentUserType();
      if (userType === UserTypeEnum.VISITOR || userType === UserTypeEnum.BOT) {
          // mqtt.connect() is NOT called
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Push Notifications">
    **Push Notifications**: Blocked for visitors/bots

    * Cannot register device tokens
    * Filtered out from notification recipient lists
    * Applies to all notification types
    * Prevents unpredictable costs from anonymous audience

    <CodeGroup>
      ```typescript theme={null}
      // Push notification registration is blocked
      import { Client, UserTypeEnum } from '@amityco/ts-sdk';

      const userType = Client.getCurrentUserType();
      if (userType === UserTypeEnum.VISITOR || userType === UserTypeEnum.BOT) {
          // registerPushNotification() throws error or no-ops
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="User Discovery">
    **User Listing/Search**: Hidden from results

    * Excluded from user search APIs
    * Not visible in followers/following lists
    * Hidden from user discovery features
    * Maintains authentic member directories

    <CodeGroup>
      ```typescript theme={null}
      // Visitors are automatically filtered from user queries
      // Your queries return only signed-in users
      const users = await UserRepository.searchUserByDisplayName({ displayName: 'John' });
      // Returns: only SIGNED_IN users, no VISITOR or BOT users
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Daily Usage Limit

Visitor and bot users share a **daily read request quota**. Once the quota is exhausted, all subsequent read API calls return error code `400323` until the quota resets.

<Info>
  **Quota**: 100 read requests per day, shared across all API endpoints — feed, events, communities, user profiles, etc. The counter resets daily. Monthly overages are a billing concern only; the SDK never receives a monthly-limit error.
</Info>

### Error Code

| Error Constant                 | TypeScript / Android Code | iOS Code                                | Trigger                                          |
| ------------------------------ | ------------------------- | --------------------------------------- | ------------------------------------------------ |
| `VISITOR_USAGE_LIMIT_EXCEEDED` | `400323`                  | `.visitorUsageLimitExceeded` / `400323` | Visitor/bot has exhausted their daily read quota |
| `VISITOR_PERMISSION_DENIED`    | `403999`                  | `.visitorPermissionDenied` / `488999`   | Visitor attempted a restricted operation         |
| `BOT_PERMISSION_DENIED`        | `403998`                  | `.botPermissionDenied` / `488998`       | Bot attempted a restricted operation             |

### SDK Event Subscription

The Android and TypeScript SDKs emit a visitor usage-limit event the first time error `400323` is detected per session. Subsequent failures within a 2-second window are deduplicated to avoid triggering the handler on simultaneous parallel requests.

<Tabs>
  <Tab title="Android">
    <CodeGroup>
      ```kotlin theme={null}
      // Subscribe to usage limit events after visitor login
      AmityCoreClient.getVisitorUsageLimitEvents()
          .observeOn(AndroidSchedulers.mainThread())
          .doOnNext { event ->
              // Navigate to sign-in or show custom error UI
              Log.d("Visitor", "Usage limit reached for user: ${event.userId}")
          }
          .subscribe()
      ```
    </CodeGroup>
  </Tab>

  <Tab title="TypeScript">
    <CodeGroup>
      ```typescript theme={null}
      import { Client } from '@amityco/ts-sdk';

      // Subscribe to usage limit events after visitor login
      const unsubscribe = Client.onVisitorUsageLimitReached(() => {
          // Navigate to sign-in or show custom error UI
          console.log('Visitor usage limit reached');
      });

      // Unsubscribe when cleaning up
      // unsubscribe();
      ```
    </CodeGroup>
  </Tab>
</Tabs>

<Note>
  The event is only emitted for `VISITOR` and `BOT` user types. Signed-in users never receive this event.
</Note>

## Data Management & Lifecycle

### Guest User Data Cleanup

To prevent accumulation of transient visitor data, social.plus automatically cleans up inactive guest users:

<AccordionGroup>
  <Accordion title="Automatic Cleanup Policy" icon="trash">
    **Schedule**: Periodic cleanup (configurable, typically 30-60 days)

    **Criteria**: Guest users inactive for the defined period

    **Process**:

    * Scheduled job runs automatically
    * Identifies inactive guest user records
    * Permanently deletes inactive guest data
    * No manual intervention required

    **What's Deleted**:

    * Guest user profile records
    * Visitor device ID associations
    * Session history
    * Any cached visitor data
  </Accordion>

  <Accordion title="Data Retention Considerations" icon="clock">
    **Active Visitors**: Continuously using visitors retain their data

    **Privacy Compliance**: Automatic cleanup supports GDPR/privacy regulations

    **Analytics Impact**: Historical analytics remain unaffected

    **Conversion Tracking**: Converted visitors (who signed up) preserve their history
  </Accordion>
</AccordionGroup>

<Note>
  **Event Availability**: Guest user events are available through existing webhook/event observation mechanisms configured in your social.plus console.
</Note>

## Implementation Best Practices

### Visitor Mode Strategy

<AccordionGroup>
  <Accordion title="When to Use Visitor Mode ✅" icon="check">
    **Recommended Scenarios:**

    1. **Public Content Discovery**
       * Community showcases and landing pages
       * SEO-optimized public content
       * Growth funnel entry points
       * Social media linked content
    2. **Conversion Optimization**
       * Allow browsing before signup
       * Demonstrate community value
       * Reduce friction in user journey
       * Track engagement before conversion
    3. **SEO & Indexing**
       * Enable search engine crawling
       * Improve content discoverability
       * Separate bot traffic from analytics
       * Optimize for organic search

    **Implementation Tips:**

    * Set clear upgrade prompts for interactive features
    * Track visitor-to-member conversion rates
    * Monitor guest traffic patterns
    * Use analytics to optimize conversion flow
  </Accordion>

  <Accordion title="When to Require Authentication ❌" icon="ban">
    **Require Sign-In For:**

    1. **Private/Sensitive Content**
       * Member-only communities
       * Personal conversations
       * Restricted content
       * Premium features
    2. **High-Value Interactions**
       * Content creation
       * Community moderation
       * Direct messaging
       * Transaction-based features
    3. **Compliance Requirements**
       * Age-restricted content
       * Regulated industries
       * Terms of service acceptance
       * User accountability needs
  </Accordion>
</AccordionGroup>

### Security Considerations

<AccordionGroup>
  <Accordion title="Production Security" icon="shield-check">
    **Always Use Secure Mode in Production:**

    <CodeGroup>
      ```typescript theme={null}
      // ✅ Production: Secure visitor mode with auth signatures
      await Client.loginAsVisitor({
        authSignature,        // Generated by your backend
        authSignatureExpiresAt, // With proper expiration
        sessionHandler,       // With token renewal logic
      });

      // ❌ Development only: Simple visitor mode
      await Client.loginAsVisitor({ sessionHandler }); // No auth signature
      ```
    </CodeGroup>

    **Why Secure Mode?**

    * Prevents unauthorized visitor creation
    * Enables server verification of device identity
    * Supports automatic token renewal
    * Maintains audit trail of visitor sessions
  </Accordion>

  <Accordion title="Visitor Device ID Privacy" icon="user-secret">
    **Privacy-conscious approach:**

    * Visitor device IDs are pseudonymous SDK identifiers
    * Visitor mode does not require a signed-in user profile
    * Automatic cleanup of inactive visitors
    * Your app remains responsible for its own privacy notice and consent requirements

    **Best Practices:**

    * Disclose visitor tracking in privacy policy
    * Provide opt-out mechanisms where required
    * Use device IDs only for platform functionality
    * Don't link device IDs to external identifiers
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Visitor login fails with permission error">
    **Symptoms**: Cannot login as visitor, permission denied errors

    **Solutions**:

    1. **Verify visitor mode is enabled** - Contact [support@social.plus](mailto:support@social.plus) if visitor mode has not been enabled for your network
    2. Check API key has visitor access permissions
    3. Ensure you're using correct region endpoint
    4. For secure mode, verify visitor secure mode is enabled for your network
    5. For secure mode, verify auth signature is correctly generated
    6. Check auth signature hasn't expired
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Authentication Guide" icon="key" href="/social-plus-sdk/getting-started/authentication">
    Learn about authenticated user login and session management
  </Card>

  <Card title="User Management" icon="user" href="/social-plus-sdk/core-concepts/user-management/overview">
    Understand user profiles and member management
  </Card>

  <Card title="Community Access Control" icon="shield" href="/social-plus-sdk/social/community/permissions">
    Configure community permissions and access levels
  </Card>

  <Card title="Analytics & Reporting" icon="chart-line" href="/analytics-and-moderation/console/analytics">
    Track visitor metrics and conversion analytics in the Console
  </Card>
</CardGroup>
