---
title: Install headless Optimizely Forms JavaScript SDK for the client app
slug: cms-12/docs/install-headless-optimizely-forms-javascript-sdk-for-the-client-app
createdAt: 2026-08-10T15:55:55.000Z
---

Precondition: `npm install -g typescript`

1. Create a React app template.

```typescript
npx create-react-app headless-form --template typescript
cd headless-form
```

2. Install Javascript SDK. Create a file `.npmrc` with content to download the package from GitHub.

```typescript
@episerver:registry=https://pkgs.dev.azure.com/EpiserverEngineering/netCore/_packaging/HeadlessForms/npm/registry
```

```typescript
npm install @episerver/forms-sdk @episerver/forms-react react-router-dom @types/react-router-dom
```

:::hint{type="info"}
**Note**
Replace the `react-router-dom` with `version =5.3.4`.
:::

3. Create file .env with content.

```typescript
REACT_APP_ENDPOINT_GET_FORM_BY_PAGE_URL=http://localhost:8000/api/React/GetFormInPageByUrl?url=
REACT_APP_HEADLESS_FORM_BASE_URL=http://localhost:8000/
REACT_APP_AUTH_BASEURL=http://localhost:8000/api/episerver/connect/token
```

4. Add code to `\src\App.tsx`.

```typescript
import "./App.css";
import { useFetch } from "./useFetch";
import { Form, FormLogin } from "@episerver/forms-react";
import {
  FormCache,
  FormConstants,
  IdentityInfo,
  extractParams,
} from "@episerver/forms-sdk";
import { useState } from "react";
import { useHistory, useLocation } from "react-router-dom";

function App() {
  const location = useLocation();
  const { language } = extractParams(window.location.pathname);
  const url = `${process.env.REACT_APP_ENDPOINT_GET_FORM_BY_PAGE_URL}${location.pathname}`;

  const { data: pageData, loading } = useFetch(url);

  const formCache = new FormCache();
  const [identityInfo, setIdentityInfo] = useState<IdentityInfo>({
    accessToken: formCache.get<string>(FormConstants.FormAccessToken),
  } as IdentityInfo);

  const history = useHistory();

  const handleAuthen = (identityInfo: IdentityInfo) => {
    setIdentityInfo(identityInfo);
  };

  return (
    <div className="App">
      {loading && <div className="loading">Loading...</div>}

      {!loading && pageData && (
        <>
          <h1>{pageData.title}</h1>
          <div className="main">
            <div className="left">
              {pageData.formKeys.map((c: any) => (
                <Form
                  key={c.reference.key}
                  formKey={c.reference.key}
                  language={language ?? "en"}
                  baseUrl={process.env.REACT_APP_HEADLESS_FORM_BASE_URL ?? "/"}
                  identityInfo={identityInfo}
                  history={history}
                  currentPageUrl={pageData.pageUrl}
                />
              ))}
            </div>
            <div className={`right`}>
              <h2>Login</h2>
              <FormLogin
                clientId="TestClient"
                authBaseUrl={process.env.REACT_APP_AUTH_BASEURL ?? ""}
                onAuthenticated={handleAuthen}
              />
            </div>
          </div>
        </>
      )}
    </div>
  );
}

export default App;

```

5. Remove `App.test.tsx` file.
6. Update code `\src\index.tsx`.

```typescript
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <Router>
      <Switch>
        <Route path="/">
          <App />
        </Route>
      </Switch>
    </Router>
  </React.StrictMode>
);
```

7. Add file `\src\useFetch.ts`.

```typescript
import { useEffect, useState } from "react";

export const useFetch = (url: string) => {
  const [data, setData] = useState<any>(null);
  const [loading, setLoading] = useState<boolean>(false);
  const [error, setError] = useState<any>(null);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      fetch(url)
        .then(async (response: Response) => {
          if (response.ok) {
            setData(await response.json());
          }
        })
        .catch((err: any) => {
          setError(err);
        })
        .finally(() => {
          setLoading(false);
        });
    };

    if (!loading) {
      fetchData();
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [url]);

  return { data, loading, error };
};

```

8. Run client site.

```typescript
npm start
```

9. Change the `frontend`'s port to `ClientApp`'s port on `ManagementSite`.
   - Update `appsettings.json` file.
   - Update on **Manage Websites**.
   - Use http instead of https on `launchSettings.json`.
