---
title: Communicate with a server
description: Learn how to fetch data from your development server to your POS UI extension.
source_url:
  html: 'https://shopify.dev/docs/apps/build/pos/communicate-with-server'
  md: 'https://shopify.dev/docs/apps/build/pos/communicate-with-server.md'
api_name: pos-ui-extensions
---

# Communicate with a server

Learn how to fetch data from your development server to your POS UI extension.

***

## Authenticating with a development server

Often, an extension running on a simulator or a device will need to communicate with a development server running on a local machine. One solution is to use the [Session API](https://shopify.dev/docs/api/pos-ui-extensions/apis/session-api) to get session tokens, and to pass these tokens to your development servers for [authentication](https://shopify.dev/docs/apps/auth/session-tokens/getting-started) using the [shopify\_app gem](https://github.com/Shopify/shopify-api-ruby).

**Caution:**

Never hardcode credentials in extension code. Extension bundles are delivered to the client and can be inspected. Keep API keys, passwords, and service tokens on your app's server, and have your extension make [authenticated requests](https://shopify.dev/docs/apps/build/authentication-authorization) for the data or action it needs. If you've already shipped one, then [revoke or rotate it immediately](https://shopify.dev/docs/apps/build/security/following-security-best-practices#secrets-in-themes-and-public-code) and release a new version.

***

## CORS considerations

Requests originating from an extension will be of origin **cdn.shopify.com** and **extensions.shopifycdn.com**. Your server needs to allow requests from both origins.

***

## HTTPS requirement

Shopify POS will refuse to fetch any non-HTTPS requests. Therefore, you must find a way to host your development server where it serves HTTPS requests. For example, a standard rails server will run on `localhost:3000`. Attempting to access this server from an Android emulator using `10.0.2.2:3000` will fail. One strategy is to use [Cloudflare Quick Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/do-more-with-tunnels/trycloudflare/), which provide an HTTPS URL to connect.

***

## Example extension

Here is an example extension that presents a Smart Grid tile. When tapped, the tile will present a modal that uses the Session API to get a session token, and then fetches a test endpoint on the development server.

### Example code

##### Tile

```jsx
import {render} from 'preact';


export default function extension() {
  render(<SmartGridTile />, document.body);
}


function SmartGridTile() {
  return (
    <s-tile
      heading="Example extension"
      onClick={() => shopify.action.presentModal()}
    />
  );
}
```

##### Modal

```jsx
import {render} from 'preact';
import {useState, useEffect} from 'preact/hooks';


export default function extension() {
  render(<SmartGridModal />, document.body);
}


function SmartGridModal() {
  const [authenticated, setAuthenticated] = useState();
  const [error, setError] = useState();
  const [sessionToken, setSessionToken] = useState();


  useEffect(() => {
    shopify.session.getSessionToken().then((token) => {
      setSessionToken(token);
      fetch('https://YOUR_DEVELOPMENT_SERVER/api/extensions/test', {
        method: 'GET',
        mode: 'cors',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${token}`,
        },
      })
        .then((response) => setAuthenticated(response.status))
        .catch(setError);
    });
  }, []);


  return (
    <s-page title="Authentication example">
      <s-box padding="base">
        <s-stack gap="base">
          <s-text>Token: {sessionToken}</s-text>
          <s-text>Authenticated: {authenticated}</s-text>
          <s-text>Error: {error}</s-text>
        </s-stack>
      </s-box>
    </s-page>
  );
}
```

***
