브라우저와 앱에서 기능 플래그 쓰기
사용자의 기기에서 실행되는 코드는 플래그 규칙을 가질 수 없습니다. 규칙에는 고객, 내부 계정, 아직 발표하지 않은 요금제가 들어갈 수 있기 때문입니다. 브라우저와 앱에서는 Mocco가 직접 플래그를 평가하고 new-checkout = true 같은 답만 돌려줍니다. 코드는 그대로 표준 OpenFeature API를 쓰고, 플래그가 바뀌면 Mocco의 프로바이더가 즉시 알려 줍니다.
이 가이드는 기능 플래그 빠른 시작처럼 기능 플래그와 환경이 있는 프로젝트가 있다고 가정합니다.
1. 기기에 보여 줄 플래그 고르기
플래그를 열고 Available to browsers and apps를 체크합니다. 이렇게 표시한 플래그만 publishable 키에 응답합니다. 다른 플래그는 존재하지 않는 것처럼 보이므로(FLAG_NOT_FOUND) 내부 플래그의 이름이 기기에 전달되지 않습니다.

2. 사이트의 오리진 허용하기
publishable 키는 페이지의 오리진이 프로젝트의 Web 앱 중 하나에 속할 때만 웹 페이지에서 동작합니다. 프로젝트의 Overview 페이지에서 Web 앱을 추가하거나(또는 기존 앱에서 Edit origins를 선택하고), 페이지를 제공하는 모든 오리진을 입력합니다. 예를 들면 https://app.acme.com이고, 로컬 개발에서는 http://localhost:5173입니다. 오리진은 스킴과 호스트로 이루어지며 경로는 없습니다.

앱(React Native)은 오리진을 보내지 않으므로 이 단계는 웹 페이지에만 해당합니다.
3. 환경 하나를 위한 publishable 키 만들기
API keys 페이지에서 flags:read 권한이 있는 Publishable 키를 만들고 읽을 환경을 고릅니다. 서버 키와 마찬가지로 정확히 환경 하나만 읽으므로, 앱의 환경마다 자체 키로 빌드하세요. publishable 키는 앱에 넣어 배포해도 안전합니다. 1단계에서 표시한 플래그의 답만 읽을 수 있습니다.

4a. 웹 페이지 또는 React 앱
OpenFeature 웹 SDK와 Mocco의 웹 프로바이더를 설치합니다.
npm install @openfeature/web-sdk @mocco/openfeature-web사용자 컨텍스트와 함께 프로바이더를 한 번 등록합니다.
import { MoccoWebProvider } from '@mocco/openfeature-web';
import { OpenFeature } from '@openfeature/web-sdk';
await OpenFeature.setContext({ targetingKey: user.id, plan: user.plan });
await OpenFeature.setProviderAndWait(new MoccoWebProvider({ publishableKey: 'mk_pub_…' }));
const showNewCheckout = OpenFeature.getClient().getBooleanValue('new-checkout', false);평가는 프로바이더가 이미 가진 답을 읽으므로 네트워크를 기다리지 않습니다. 프로바이더는 모든 답을 한 번의 요청으로 가져오고 Mocco의 변경 스트림을 구독합니다. 콘솔에서 플래그를 바꾸면 열려 있는 페이지가 1~2초 안에 갱신되고 OpenFeature가 PROVIDER_CONFIGURATION_CHANGED를 발생시킵니다. 스트림에 연결할 수 없으면 대신 60초마다 확인합니다(pollInterval). 탭이 다시 보일 때도 확인하며, 마지막 답을 localStorage에 보관해 새로고침했을 때 네트워크가 응답하기 전에 그 답을 보여 줍니다.
사용자가 로그인하거나 요금제를 바꾸면 OpenFeature.setContext(...)를 다시 호출하세요. 프로바이더가 새 컨텍스트의 답을 가져옵니다.
React
@openfeature/react-sdk를 쓰면 앱을 한 번 감싸고 훅으로 플래그를 읽습니다. 플래그가 바뀌면 컴포넌트가 다시 렌더링됩니다.
import { MoccoWebProvider } from '@mocco/openfeature-web';
import { OpenFeature, OpenFeatureProvider, useBooleanFlagValue } from '@openfeature/react-sdk';
OpenFeature.setProvider(new MoccoWebProvider({ publishableKey: 'mk_pub_…' }));
export function App() {
return (
<OpenFeatureProvider>
<Checkout />
</OpenFeatureProvider>
);
}
function Checkout() {
const isNew = useBooleanFlagValue('new-checkout', false);
return isNew ? <NewCheckout /> : <OldCheckout />;
}4b. React Native 앱
OpenFeature SDK, Mocco의 React Native 프로바이더, 프로바이더가 쓰는 저장소 및 이벤트 스트림 라이브러리를 설치합니다.
npm install @openfeature/web-sdk @openfeature/react-sdk @mocco/openfeature-react-native \
@react-native-async-storage/async-storage react-native-sseReact Native에는 localStorage, 페이지 가시성, EventSource가 없으므로 직접 넘겨 줍니다.
import AsyncStorage from '@react-native-async-storage/async-storage';
import { MoccoReactNativeProvider } from '@mocco/openfeature-react-native';
import { OpenFeature, OpenFeatureProvider, useBooleanFlagValue } from '@openfeature/react-sdk';
import { AppState } from 'react-native';
import EventSource from 'react-native-sse';
OpenFeature.setProvider(
new MoccoReactNativeProvider({
publishableKey: 'mk_pub_…',
storage: AsyncStorage,
appState: AppState,
EventSource,
}),
);그다음에는 위 React 예제처럼 OpenFeatureProvider와 훅을 씁니다.
각 항목의 역할은 다음과 같습니다.
**
storage**는 마지막 답을 기기에 보관합니다. 다음 실행 때 앱은 오프라인이어도 그 답으로 바로 시작하고 백그라운드에서 갱신합니다. Mocco에 연결할 수 없는 동안 프로바이더는PROVIDER_STALE을 보고하며 저장된 사본으로 계속 응답합니다.**
appState**는 앱이 포그라운드로 돌아올 때마다 새 답을 가져오고, 백그라운드에서는 확인을 멈춥니다.**
EventSource**는 앱이 열려 있는 동안 Mocco의 변경 스트림을 구독하므로 변경이 몇 초 안에 도착합니다. 없으면 프로바이더는 앱이 활성 상태인 동안 60초마다 확인합니다(pollIntervalMs).
저장된 답도 없고 네트워크도 없는 맨 처음 실행만 답 없이 시작합니다. 이때는 모든 플래그가 코드의 기본값을 반환합니다.
서버 측: Vercel Flags SDK
Flags SDK를 쓰는 Next.js 앱에서는 secret 키와 Mocco의 서버 프로바이더로 서버에서 평가합니다. Flags SDK의 OpenFeature 어댑터를 거칩니다.
npm install flags @flags-sdk/openfeature @openfeature/server-sdk @mocco/openfeature-serverimport { createOpenFeatureAdapter } from '@flags-sdk/openfeature';
import { MoccoProvider } from '@mocco/openfeature-server';
import { OpenFeature } from '@openfeature/server-sdk';
import { flag } from 'flags/next';
const mocco = createOpenFeatureAdapter(async () => {
await OpenFeature.setProviderAndWait(new MoccoProvider({ secretKey: process.env.MOCCO_FLAGS_KEY! }));
return OpenFeature.getClient();
});
export const newCheckout = flag<boolean>({
key: 'new-checkout',
defaultValue: false,
adapter: mocco.booleanValue(),
identify: async () => ({ targetingKey: (await currentUser()).id }),
});그러면 서버 컴포넌트나 라우트에서 await newCheckout()이 기능 플래그 빠른 시작에서 설명한 대로 메모리에서 평가됩니다.