# Store data (https://docs.salla.dev/twilight/react/data/store)





Read this page when you need to know what the store object looks like: which fields exist, which can be missing, and where to find things like languages and currencies.

## Where you read it [#where-you-read-it]

There are two ways to get the same store object.

| You write                        | You get                                     |
| -------------------------------- | ------------------------------------------- |
| [`useStore()`](https://docs.salla.dev/twilight/react/hooks/use-store) | The store fields plus a `refresh()` method. |
| `useTwilight().store`            | The store fields only.                      |

The engine loads the store once per request from the `store/settings` API and hands it to the provider at the root of your app. It is available in server rendering and in the browser, from the first render.

Languages and currencies are **not** inside the store object. They come from the same API response and you read them from `useTwilight().settings` (see [Common tasks](#common-tasks)). The theme object is covered in [Theme data](https://docs.salla.dev/twilight/react/data/theme).

```tsx title="app/components/layout/StoreBadge.tsx"
import { useStore } from '@salla.sa/twilight-theme-engine/hooks/useStore';

export function StoreBadge() {
  const { name, logo, url, contacts, settings } = useStore();

  return (
    <a href={url}>
      <img src={logo} alt={name} />
      {contacts.email && <span>{contacts.email}</span>}
      {settings.rating_enabled && <span>Rated by customers</span>}
    </a>
  );
}
```

## The full object [#the-full-object]

This is the store of the public demo store `1510890315`, shortened: long arrays are cut to a few items and long strings are trimmed. Search it, expand what you need, and click a key to copy its path. Notes sit next to the less obvious fields.

<JsonExplorer data="storeExample" title="Store object (demo store 1510890315)" />

<Callout type="info" title="Typed and untyped fields">
  The `Store` type describes the fields themes read. The API can return more (for example extra `settings.rating` options). TypeScript does not know about those, so read them with a cast or your own type.
</Callout>

## Fields [#fields]

The tables below are generated from the engine's `Store` type. Nested objects get their own table, named by their path (`settings.auth`, `settings.cart`, and so on). Example values are in the explorer above.

{/* types: ../../../../../theme-engine/src/types/index.ts#Store depth=3 */}

| Field                | Type                                                           | Description                                                                            |
| -------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `id`                 | `number`                                                       | Store id.                                                                              |
| `name`               | `string`                                                       | Store name, as the merchant typed it.                                                  |
| `username`           | `string`                                                       | Store username.                                                                        |
| `description`        | `string`                                                       | Store description, as HTML rather than plain text.                                     |
| `slogan?`            | `string`                                                       | Store slogan.                                                                          |
| `logo`               | `string`                                                       | Logo image URL.                                                                        |
| `url`                | `string`                                                       | Store home URL. On a multilingual store it ends with the language prefix (`/ar/`).     |
| `api?`               | `string`                                                       | Base URL of the store API.                                                             |
| `icon`               | `string`                                                       | Icon image URL.                                                                        |
| `favicon?`           | `string`                                                       | Favicon URL. Marked for removal.                                                       |
| `about?`             | `string`                                                       | Longer "about the store" text.                                                         |
| `created_at?`        | `string`                                                       | When the store was created.                                                            |
| `updated_at?`        | `string`                                                       | When the store was last updated.                                                       |
| `meta?`              | `{ title?: string; description?: string; keywords?: string; }` | Default SEO values for pages that set none. Empty strings when the merchant set none.  |
| `settings`           | `StoreSettings`                                                | Store-level settings (auth, cart, product, ratings and so on).                         |
| `contacts`           | `StoreContacts`                                                | Contact details the store shows to customers.                                          |
| `social`             | `StoreSocial`                                                  | Links to the store's social media profiles.                                            |
| `country`            | `string`                                                       | Store's default country code (uppercase ISO, e.g., "SA").                              |
| `store_country?`     | `string`                                                       | Country the store operates in (uppercase ISO, e.g., "SA").                             |
| `ray?`               | `number`                                                       | Internal platform request value; nothing in a theme should depend on it.               |
| `features?`          | `string[]`                                                     | Platform feature flags that are on for this store.                                     |
| `apps?`              | `StoreApps`                                                    | Mobile app download links.                                                             |
| `template?`          | `string \| null`                                               | Reserved by the platform; usually null.                                                |
| `scope?`             | `StoreScope \| null`                                           | The selected market or branch, or null when the store has none.                        |
| `is_merchant?`       | `boolean`                                                      | Whether the visitor is the merchant. Marked for removal: rely on `theme.mode` instead. |
| `support_pickup?`    | `boolean`                                                      | Whether the store offers pickup (mirrors `shipping.support_pickup`).                   |
| `shipping?`          | `StoreShipping`                                                | Shipping and delivery options the store offers.                                        |
| `rating?`            | `{ total: number; stars: number; }`                            | Store-wide rating summary.                                                             |
| `ratings?`           | `{ stars: number; total: number; }[]`                          | Rating distribution: how many ratings gave each star value.                            |
| `order_instruction?` | `StoreOrderInstruction`                                        | Order confirmation page messages (HTML strings).                                       |

#### `meta` [#meta]

| Field          | Type     | Description               |
| -------------- | -------- | ------------------------- |
| `title?`       | `string` | Default page title.       |
| `description?` | `string` | Default page description. |
| `keywords?`    | `string` | Default page keywords.    |

#### `settings` [#settings]

| Field                       | Type                                                                                          | Description                                                                                                                                |
| --------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `auth`                      | `{ email_allowed: boolean; mobile_allowed: boolean; is_email_required: boolean; countrie...`  | Sign-in and registration options.                                                                                                          |
| `cart`                      | `{ apply_coupon_enabled: boolean; basket_gap?: boolean; multi_coupon?: boolean; }`            | Cart options.                                                                                                                              |
| `product`                   | `{ total_sold_enabled: number; manual_quantity?: boolean; fit_type?: 'cover' \| 'contain'...` | Product page and listing options.                                                                                                          |
| `category`                  | `{ testimonial_enabled: boolean; }`                                                           | Category page options.                                                                                                                     |
| `payments?`                 | `string[]`                                                                                    | Enabled payment methods.                                                                                                                   |
| `arabic_numbers_enabled`    | `boolean`                                                                                     | Show Arabic-Indic digits.                                                                                                                  |
| `content_copyright?`        | `boolean`                                                                                     | Content copy protection is on.                                                                                                             |
| `use_sar_symbol?`           | `boolean`                                                                                     | Show the Saudi riyal symbol instead of the currency code.                                                                                  |
| `is_multilingual`           | `boolean`                                                                                     | The store offers more than one language.                                                                                                   |
| `currencies_enabled`        | `boolean`                                                                                     | The store offers more than one currency.                                                                                                   |
| `rating_enabled`            | `boolean`                                                                                     | Ratings are turned on for the store.                                                                                                       |
| `rating?`                   | `{ is_enabled: boolean; show_on_category: boolean; show_on_product: boolean; can_rate_st...`  | Rating and review options.                                                                                                                 |
| `blog?`                     | `{ is_enabled: boolean; allow_likes_and_comments: boolean; }`                                 | Blog options.                                                                                                                              |
| `is_loyalty_enabled?`       | `boolean`                                                                                     | The loyalty program is on.                                                                                                                 |
| `keys?`                     | `{ maps?: string; gtm?: string[]; sift?: string; }`                                           | Public keys for third-party services.                                                                                                      |
| `is_salla_gateway?`         | `boolean`                                                                                     | The store uses the Salla payment gateway.                                                                                                  |
| `upload_size?`              | `number`                                                                                      | Maximum upload size.                                                                                                                       |
| `tax?`                      | `{ number?: string; certificate?: string \| null; taxable_prices_enabled: boolean; }`         | Tax details.                                                                                                                               |
| `certificate?`              | `{ id: string; } \| null`                                                                     | Commerce certificate details, or null.                                                                                                     |
| `made_in_ksa?`              | `boolean`                                                                                     | Show the "Made in KSA" mark.                                                                                                               |
| `commercial_number?`        | `string \| null`                                                                              | Commercial registration number, or null.                                                                                                   |
| `freelance_number?`         | `string \| null`                                                                              | Freelance license number, or null.                                                                                                         |
| `buy_now?`                  | `string \| BuyNowSettings \| null`                                                            | Fast-checkout (Apple Pay style) configuration object, or null when off. Typed `string \| null` in older releases; the API sends an object. |
| `installments?`             | `string \| unknown[] \| Record<string, unknown> \| null`                                      | Installment providers. An empty array means none, and an empty array is truthy.                                                            |
| `quick_order?`              | `string \| Record<string, unknown> \| null`                                                   | Quick-order configuration, or null when off.                                                                                               |
| `bullet_delivery?`          | `string \| Record<string, unknown> \| null`                                                   | Fast ("bullet") delivery configuration, or null when off.                                                                                  |
| `ticketing_system_enabled?` | `boolean`                                                                                     | Support tickets are on.                                                                                                                    |
| `opening_hours?`            | `OpeningHoursSettings`                                                                        | Opening hours for receiving orders. Not yet sent by the API.                                                                               |
| `features?`                 | `{ price_quote?: boolean; 'pre-order-campaigns'?: boolean; }`                                 | Feature flags. Not yet sent by the API.                                                                                                    |

#### `settings.auth` [#settingsauth]

| Field                        | Type       | Description                                                                                           |
| ---------------------------- | ---------- | ----------------------------------------------------------------------------------------------------- |
| `email_allowed`              | `boolean`  | Customers can sign in with email.                                                                     |
| `mobile_allowed`             | `boolean`  | Customers can sign in with a mobile number.                                                           |
| `is_email_required`          | `boolean`  | Email is required when registering.                                                                   |
| `countries?`                 | `string[]` | Country codes allowed for mobile numbers, lowercase.                                                  |
| `force_login?`               | `boolean`  | Visitors must sign in to browse the store.                                                            |
| `whatsapp_allowed?`          | `boolean`  | Customers can sign in through WhatsApp.                                                               |
| `whatsapp_countries?`        | `string[]` | Country codes where WhatsApp sign-in is offered.                                                      |
| `whatsapp_merchant_allowed?` | `boolean`  | Whether the merchant has enabled WhatsApp sign-in.                                                    |
| `user_country?`              | `string`   | Visitor's detected country (uppercase ISO), e.g. "DE".                                                |
| `config?`                    | `unknown`  | Extra sign-in configuration sent by the platform; its shape is not typed, and it is null when unused. |

#### `settings.cart` [#settingscart]

| Field                  | Type      | Description                          |
| ---------------------- | --------- | ------------------------------------ |
| `apply_coupon_enabled` | `boolean` | Show the coupon field in the cart.   |
| `basket_gap?`          | `boolean` | Platform flag for the cart layout.   |
| `multi_coupon?`        | `boolean` | More than one coupon can be applied. |

#### `settings.product` [#settingsproduct]

| Field                          | Type                                                                            | Description                                                                                   |
| ------------------------------ | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `total_sold_enabled`           | `number`                                                                        | Show how many units were sold. It is 1 or 0, not a boolean.                                   |
| `manual_quantity?`             | `boolean`                                                                       | Customers can type the quantity instead of using a stepper.                                   |
| `fit_type?`                    | `"contain" \| "cover" \| null`                                                  | How product images fill their frame; null when not set.                                       |
| `related_products_enabled?`    | `boolean`                                                                       | Show related products.                                                                        |
| `filters?`                     | `boolean \| ProductFiltersSettings \| null`                                     | Switches for the listing filters, one per filter (`{ category_id: true, price: true, ... }`). |
| `product-recommendation-type?` | `string`                                                                        | Kind of product recommendations to show. The key has hyphens, so read it with brackets.       |
| `bought_together?`             | `boolean`                                                                       | Show "bought together" products.                                                              |
| `show_comments?`               | `boolean`                                                                       | Show product comments.                                                                        |
| `user_can_comment?`            | `boolean`                                                                       | Customers can comment on products.                                                            |
| `show_price_as_dash?`          | `boolean`                                                                       | Hide prices and show a dash instead.                                                          |
| `notify_options_availability?` | `boolean`                                                                       | Offer "notify me" for sold-out options.                                                       |
| `show_special_offers?`         | `boolean`                                                                       | Show special offers on the product.                                                           |
| `show_more?`                   | `boolean`                                                                       | Show the "show more" control.                                                                 |
| `availability_notify?`         | `{ email: boolean; sms: boolean; mobile: boolean; whatsapp: boolean; } \| null` | Channels offered for "notify me when available", or null when the feature is off.             |

#### `settings.product.availability_notify` [#settingsproductavailability_notify]

| Field      | Type      | Description                    |
| ---------- | --------- | ------------------------------ |
| `email`    | `boolean` | Notify by email.               |
| `sms`      | `boolean` | Notify by SMS.                 |
| `mobile`   | `boolean` | Notify by mobile notification. |
| `whatsapp` | `boolean` | Notify by WhatsApp.            |

#### `settings.category` [#settingscategory]

| Field                 | Type      | Description                          |
| --------------------- | --------- | ------------------------------------ |
| `testimonial_enabled` | `boolean` | Show testimonials on category pages. |

#### `settings.rating` [#settingsrating]

| Field                    | Type      | Description                                 |
| ------------------------ | --------- | ------------------------------------------- |
| `is_enabled`             | `boolean` | Ratings are on.                             |
| `show_on_category`       | `boolean` | Show ratings on category pages.             |
| `show_on_product`        | `boolean` | Show ratings on product pages.              |
| `can_rate_store`         | `boolean` | Customers can rate the store.               |
| `can_rate_product`       | `boolean` | Customers can rate products.                |
| `can_rate_shipping`      | `boolean` | Customers can rate shipping.                |
| `show_rating_summary`    | `boolean` | Show the rating summary block.              |
| `show_recommendation`    | `boolean` | Show the "would you recommend" question.    |
| `allow_likes`            | `boolean` | Reviews can be liked.                       |
| `allow_attach_images`    | `boolean` | Reviews can include images.                 |
| `allow_contact_support`  | `boolean` | Show a contact-support action on reviews.   |
| `allow_update`           | `boolean` | Customers can edit their review.            |
| `update_period`          | `number`  | Number of days a review can be edited.      |
| `can_customer_hide_name` | `boolean` | Reviewers can hide their name.              |
| `visitor_can_comment`    | `boolean` | Visitors who are not signed in can comment. |
| `page_feedback_enabled`  | `boolean` | Page feedback is on.                        |

#### `settings.blog` [#settingsblog]

| Field                      | Type      | Description                               |
| -------------------------- | --------- | ----------------------------------------- |
| `is_enabled`               | `boolean` | The blog is on.                           |
| `allow_likes_and_comments` | `boolean` | Readers can like and comment on articles. |

#### `settings.keys` [#settingskeys]

| Field   | Type       | Description                                                           |
| ------- | ---------- | --------------------------------------------------------------------- |
| `maps?` | `string`   | Maps API key for the storefront.                                      |
| `gtm?`  | `string[]` | Google Tag Manager container ids.                                     |
| `sift?` | `string`   | Sift Science beacon key for fraud detection. Not yet sent by the API. |

#### `settings.tax` [#settingstax]

| Field                    | Type             | Description                         |
| ------------------------ | ---------------- | ----------------------------------- |
| `number?`                | `string`         | Tax registration number.            |
| `certificate?`           | `string \| null` | Tax certificate image URL, or null. |
| `taxable_prices_enabled` | `boolean`        | Prices include tax.                 |

#### `settings.certificate` [#settingscertificate]

| Field | Type     | Description              |
| ----- | -------- | ------------------------ |
| `id`  | `string` | Commerce certificate id. |

#### `settings.opening_hours` [#settingsopening_hours]

| Field      | Type                       | Description                                                                                                |
| ---------- | -------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `enabled?` | `boolean`                  | The store only takes orders during opening hours.                                                          |
| `hours?`   | `Record<string, string[]>` | Time ranges per lowercase day name (monday, tuesday, ...). A day with no entry or an empty list is closed. |

#### `settings.features` [#settingsfeatures]

| Field                  | Type      | Description                          |
| ---------------------- | --------- | ------------------------------------ |
| `price_quote?`         | `boolean` | Customers can ask for a price quote. |
| `pre-order-campaigns?` | `boolean` | Pre-order campaigns are available.   |

#### `contacts` [#contacts]

| Field       | Type     | Description              |
| ----------- | -------- | ------------------------ |
| `mobile?`   | `string` | Mobile number.           |
| `phone?`    | `string` | Phone number.            |
| `email?`    | `string` | Support email address.   |
| `whatsapp?` | `string` | WhatsApp link or number. |
| `telegram?` | `string` | Telegram link.           |

#### `social` [#social]

| Field        | Type     | Description               |
| ------------ | -------- | ------------------------- |
| `instagram?` | `string` | Instagram profile link.   |
| `snapchat?`  | `string` | Snapchat profile link.    |
| `twitter?`   | `string` | X (Twitter) profile link. |
| `youtube?`   | `string` | YouTube channel link.     |
| `facebook?`  | `string` | Facebook page link.       |
| `pinterest?` | `string` | Pinterest profile link.   |
| `maroof?`    | `string` | Maroof page link.         |
| `whatsapp?`  | `string` | WhatsApp link.            |
| `tiktok?`    | `string` | TikTok profile link.      |

#### `apps` [#apps]

| Field         | Type     | Description       |
| ------------- | -------- | ----------------- |
| `appstore?`   | `string` | App Store link.   |
| `googleplay?` | `string` | Google Play link. |

#### `scope` [#scope]

| Field         | Type                               | Description                                                               |
| ------------- | ---------------------------------- | ------------------------------------------------------------------------- |
| `id?`         | `number`                           | Scope id.                                                                 |
| `name`        | `string`                           | Market or branch name.                                                    |
| `selected?`   | `boolean`                          | This scope is the active one.                                             |
| `type?`       | `string`                           | Scope type, such as a branch.                                             |
| `is_open?`    | `boolean`                          | The scope is open.                                                        |
| `display_as`  | `"default" \| "inline" \| "popup"` | How the scope selector is shown.                                          |
| `languages?`  | `string[]`                         | Available language codes (lowercase, e.g., \["ar", "en"])                 |
| `currencies?` | `string[]`                         | Available currency codes (e.g., \["SAR", "USD"])                          |
| `countries?`  | `string[]`                         | Available country codes (uppercase ISO, e.g., \["SA", "AE"])              |
| `always_ask?` | `boolean`                          | Ask the visitor to choose a scope.                                        |
| `allocation?` | `unknown`                          | Allocation details sent by the platform, or null; its shape is not typed. |

#### `shipping` [#shipping]

| Field                       | Type      | Description                                                        |
| --------------------------- | --------- | ------------------------------------------------------------------ |
| `delivery_location?`        | `unknown` | Delivery location details, or null when the store has none.        |
| `express_delivery_promise?` | `unknown` | Express-delivery promise details, or null when the store has none. |
| `support_pickup?`           | `boolean` | Whether the store offers pickup.                                   |
| `has_bullet_delivery_tag?`  | `boolean` | Whether products show the fast-delivery ("bullet") tag.            |

#### `rating` [#rating]

| Field   | Type     | Description                               |
| ------- | -------- | ----------------------------------------- |
| `total` | `number` | Number of ratings the store has received. |
| `stars` | `number` | Average star rating.                      |

#### `ratings` [#ratings]

| Field   | Type     | Description                                  |
| ------- | -------- | -------------------------------------------- |
| `stars` | `number` | The star value (for example 5).              |
| `total` | `number` | Number of ratings that gave this star value. |

#### `order_instruction` [#order_instruction]

| Field                                 | Type     | Description                                      |
| ------------------------------------- | -------- | ------------------------------------------------ |
| `thank_title?`                        | `string` | Heading of the order confirmation page.          |
| `order_instructions_payment_waiting?` | `string` | Message shown while the order waits for payment. |
| `order_instructions_under_review?`    | `string` | Message shown while the order is under review.   |
| `order_instructions_completed?`       | `string` | Message shown once the order is completed.       |

{/* /types */}

The API still sends more than the type lists: for example `settings.rating` also carries video and points options (`allow_attach_videos`, `required_attach_images`, `rating_store_points`). `buy_now`, `installments`, `quick_order` and `bullet_delivery` can be an object, an array or `null`, so check before you use them (in the demo, `buy_now` is an object and `installments` is `[]`).

`settings.features` is not the top-level `features` array of strings. `settings.opening_hours` is read by [`useOpeningHours`](#is-the-store-open-right-now). `scope` is `null` unless the store uses markets or branches; the demo store has none, so there is no real example in the explorer.

### `refresh` [#refresh]

Only on `useStore()`. `refresh(): Promise<void>` re-reads `store` from the Salla SDK config and merges it, one level deep, over the current store. It does nothing when the SDK is not loaded yet, and ignores errors.

## Common tasks [#common-tasks]

### Is the store multilingual, and which languages? [#is-the-store-multilingual-and-which-languages]

`is_multilingual` is on the store. The list of languages is on `settings`, as an array.

```tsx
import { useTwilight } from '@salla.sa/twilight-theme-engine';

function Languages() {
  const { store, settings, locale } = useTwilight();
  if (!store.settings?.is_multilingual) return null;

  return (
    <ul>
      {settings.languages?.map((lang) => (
        <li key={lang.code} aria-current={lang.code === locale}>
          {lang.name} {lang.is_rtl ? '(RTL)' : ''}
        </li>
      ))}
    </ul>
  );
}
```

Demo values: `{ "name": "العربية", "code": "ar", "is_rtl": true, "country_code": "sa", "url": "https://assets.salla.sa/images/flags/ar.svg" }`. The `url` is the flag icon, not a page. The engine also adds `iso_code`, equal to `code`. See [Languages and RTL](https://docs.salla.dev/twilight/react/guide/languages-and-rtl).

### Which currencies are available? [#which-currencies-are-available]

`settings.currencies` is an object keyed by currency code. `amount` is the exchange rate against the store currency (in the demo, `USD.amount` is `0.267589` and `SAR.amount` is `1`). To format prices, use [`useMoney`](https://docs.salla.dev/twilight/react/hooks/use-money).

```tsx
const { store, settings } = useTwilight();
const codes = store.settings?.currencies_enabled ? Object.keys(settings.currencies ?? {}) : [];
// ["AED", "AUD", "BHD", …, "SAR", "USD"]
```

### Do customers sign in by email or mobile? [#do-customers-sign-in-by-email-or-mobile]

```tsx
const { auth } = useStore().settings;
const methods = [auth.email_allowed && 'email', auth.mobile_allowed && 'mobile'].filter(Boolean);
// demo store: ["email"]
```

When `force_login` is `true`, send visitors to sign in before they browse.

### Is the store open right now? [#is-the-store-open-right-now]

`opening_hours` is passed to `useOpeningHours`, which returns `isOpen`, `isEnabled`, `nextOpen` and `nextOpenFormatted`. It treats the store as open when opening hours are not enabled.

```tsx
import { useStore } from '@salla.sa/twilight-theme-engine/hooks/useStore';
import { useOpeningHours } from '@salla.sa/twilight-theme-engine/hooks';

function ClosedNotice() {
  const { settings } = useStore();
  const { isOpen, nextOpenFormatted } = useOpeningHours(settings.opening_hours);
  return isOpen ? null : <p>We are closed. We open {nextOpenFormatted}.</p>;
}
```

### Is the store in maintenance? [#is-the-store-in-maintenance]

When the merchant closes the store from the dashboard (or the platform closes it, or one market is closed), the settings response carries `maintenance: true` and `maintenance_details`: the merchant's `title` and `message` (plain text), and `button_*` fields that are `null` for customers.

You do not have to handle it. The engine decides per request who sees what, the way the Twig storefront does: a customer gets the maintenance page (`MaintenancePage` from `@salla.sa/twilight-theme-engine/store`) in place of your layout, with a `503` status, and nothing else renders, not even the Salla SDK. The merchant gets the store as usual, with the SDK's maintenance bar on top.

```tsx
const { settings } = useTwilight();
settings.maintenance; // true while the store is closed, for the merchant too
settings.maintenance_details?.title; // what the merchant wrote
```

#### A store that has not launched yet [#a-store-that-has-not-launched-yet]

Until the merchant finishes launching the store, the settings say `maintenance: true` too, but `maintenance_details` then holds the merchant's own "finish launching" notice, which the API sends to every visitor. The engine marks these settings `launched: false`, and `MaintenancePage` shows customers the platform's launching-soon page instead: the store's logo, "The store is launching soon" in the platform's words, and the store's contacts. It never shows them that notice.

```tsx
settings.launched; // false while the store has not launched yet; absent otherwise
```

#### How the engine tells the merchant from a customer [#how-the-engine-tells-the-merchant-from-a-customer]

The decision is made once per request, in the root route's `beforeLoad`, from the settings and the request alone:

1. The dashboard's "view store" button (and the partners portal) opens the store with `?utm_source=dashboard&identifier=<store id>` (`portal` for the portal). When `identifier` is this store's `store.id`, the request is the merchant's. The engine answers with the store and sets a session cookie, `salla_view_as=<store id>`, so the browser is remembered as the merchant until it closes, as the Twig storefront's PHP session was.
2. A request carrying that cookie for this store is the merchant's too. The cookie opens only the store it was set for.
3. A session the backend marks as a theme preview (`theme.mode === 'preview'`) always sees the store.
4. Anything served from the preview host (`preview.salla.design`) always sees the store, closed or not launched yet. The dashboard's theme editor frames your theme there, and a frame on another site carries neither the link from step 1 nor the cookie from step 2, so the host is what says it is a preview. It holds on every page of the preview, not only the first, as the Twig storefront's own preview hosts do. A merchant's domain, `salla.sa` and a dev server are not the preview host, so they are decided by the other steps. On the preview host the engine also initialises the Salla SDK with `maintenance: false`, so the SDK's merchant maintenance bar is not drawn over the page being edited. Only the SDK's copy changes: the settings you read with `useTwilight()` stay as the API sent them, `maintenance: true` included.
5. Everyone else gets the maintenance page and a `503`, so search engines keep the store indexed as temporarily unavailable.

#### While you develop [#while-you-develop]

Your dev server renders against a real store, so a closed store shows you the maintenance page too. In development the engine pins a bar to the top of it with a link, "View the store as the merchant": the dashboard's link from step 1, for this store. Click it once, and the rest of the browser session renders the store. A private window gives you the customer's page back, which is how you check your own `maintenancePage` below. The bar exists only on the dev server; production builds drop it.

#### Your own maintenance page [#your-own-maintenance-page]

To show your own page instead of the engine's, pass it to the provider beside `layout`. It takes no props and renders alone: no layout, no route, no SDK. It renders for a store that has not launched yet too, so check `settings.launched` before you show `maintenance_details`.

```tsx title="app/routes/__root.tsx"
import { TwilightProvider, useTwilight } from '@salla.sa/twilight-theme-engine';

function ClosedPage() {
  const { store, settings } = useTwilight();
  return (
    <main>
      <img src={store.logo} alt={store.name} />
      {settings.launched === false ? (
        <h1>Launching soon</h1>
      ) : (
        <>
          <h1>{settings.maintenance_details?.title}</h1>
          <p>{settings.maintenance_details?.message}</p>
        </>
      )}
    </main>
  );
}

<TwilightProvider translations={themeTranslations} layout={MainLayout} maintenancePage={ClosedPage}>
  <Outlet />
</TwilightProvider>;
```

### Which payment methods and features are on? [#which-payment-methods-and-features-are-on]

```tsx
const { settings, features = [] } = useStore();
const acceptsCash = settings.payments?.includes('cod');
const guestCheckout = features.includes('guest-checkout');
```

### Free shipping and cart settings [#free-shipping-and-cart-settings]

Free shipping progress is part of the cart, not the store. See [Cart data](https://docs.salla.dev/twilight/react/data/cart). Store-level cart switches are in `settings.cart`, for example `settings.cart.apply_coupon_enabled`.

## Gotchas [#gotchas]

* **Many fields are optional.** `slogan`, `about`, `favicon`, `api`, `scope`, `opening_hours`, `social.*` and `contacts.*` can be missing. Use optional chaining and test for presence before you render a link.
* **Types are looser than the data.** Several settings (`filters`, `buy_now`, `installments`) are unions of a boolean or string, an object and `null`, so narrow them before use. Some real fields are not typed at all.
* **`store.id` is a number**, but ids on other objects, such as `certificate.id`, are strings. Compare with the right type, or convert before you compare.
* **Some setting keys are not valid identifiers.** `settings.product['product-recommendation-type']` and `settings.features['pre-order-campaigns']` need bracket access.
* **Flags that are numbers.** `settings.product.total_sold_enabled` is `1` or `0`.
* **Language-dependent values.** The API response follows the page language, so `url` carries the language prefix (`/en/`). `name` and `description` are what the merchant typed and are not translated.
* **`description` is HTML.** Sanitise it or render it with care.
* **Empty store object.** If the provider is created without settings, `store` is `{}` until settings arrive, so `store.settings` is `undefined`. Use `store.settings?.…` in code that can run that early.
* **Server and browser see the same store.** It comes from the settings loaded for the request, so server and first browser render match. `refresh()` only exists in the browser, because it needs the Salla SDK.
* **`useStore()` returns a new object on every render.** Use `useTwilight().store`, which keeps its identity until `refresh()`, or depend on the fields you read, in effect and memo dependencies.
* **`settings` on `useTwilight()` is not `store.settings`.** `useTwilight().settings` is the whole settings response (store, theme, `languages`, `currencies`, and more). `store.settings` is only the store-level settings group.

## Next [#next]

* [`useStore`](https://docs.salla.dev/twilight/react/hooks/use-store) is the hook reference.
* [Theme data](https://docs.salla.dev/twilight/react/data/theme) describes the theme object next to the store.
* [Product data](https://docs.salla.dev/twilight/react/data/product) and [Cart data](https://docs.salla.dev/twilight/react/data/cart) describe the other objects your components read.
