> For the complete documentation index, see [llms.txt](https://docs.hackle.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hackle.io/en/development-guide/react-native/webapp-integration/react-native-web-app-intergration-deprecated.md).

# WebApp Integration (deprecated)

{% hint style="danger" %}
This document has been deprecated.
{% endhint %}

When rendering your website via `WebView`, you can use the Hackle JavaScript SDK included in the website with the same functionality as the Hackle React Native SDK — without any changes to your website code — by applying the settings below.

#### The following tasks are required for React Native WebApp Integration.

* Add a bridge at the point where WebView is rendered in the React Native SDK.
* Wrap the JavaScript SDK used in WebView to create a ReactNative-specific Client.

## React Native

Please complete the following tasks on the client side where the React Native SDK is installed.

{% tabs %}
{% tab title="3.26.0 and above" %}
{% hint style="info" %}
Github: [0.0.3](https://github.com/hackle-io/hackle-react-native-web-app-helper/blob/0.0.3/react-native/src/useHackleWebviewManager.ts)
{% endhint %}

1. Add `useHackleWebviewManager` from the source code above to your project. 1-1. If you already have an existing `useHackleWebviewManager`, overwrite the script.
2. Pass props to WebView via the `useHackleWebviewManager` hook.
   {% endtab %}

{% tab title="3.25.0 and below" %}
{% hint style="info" %}
Github: [0.0.1](https://github.com/hackle-io/hackle-react-native-web-app-helper/blob/0.0.1/react-native-webview-javascript-integration/react-native/useHackleWebviewManager.js)
{% endhint %}

1. Add `useHackleWebviewManager` from the source code above to your project.
2. Pass props to WebView via the `useHackleWebviewManager` hook.
   {% endtab %}
   {% endtabs %}

### ReactNative WebView JS Injection

<table><thead><tr><th width="250">Item</th><th>Description</th></tr></thead><tbody><tr><td><code>hackleInjectedJavaScript</code></td><td>Sends a message from the WebView's JavaScript SDK to the React Native SDK to process the function on its behalf.</td></tr><tr><td><code>onHackleMessage</code></td><td>Processes messages received from the JavaScript SDK in the React Native SDK.</td></tr></tbody></table>

```jsx
const hackleClient = createInstance("YOUR_SDK_KEY");

function App() {
  const webviewRef = useRef(null);
  const { hackleInjectedJavaScript, onHackleMessage, isHackleMessageEvent } =
        useHackleWebviewManager({
          postMessage: (message) => webviewRef.current?.postMessage(message),
          hackleClient,
        });

  return (
      <HackleProvider hackleClient={hackleClient}>
        <SafeAreaView>
          <View>
            <WebView
              ref={webviewRef}
              source={{ uri: "web_url" }}
              injectedJavaScriptBeforeContentLoaded={hackleInjectedJavaScript}
              onMessage={(e) => {
                if (isHackleMessageEvent(e)) {
                  onHackleMessage(e.nativeEvent.data);
                  return;
                }
              }}
            />
          </View>
        </SafeAreaView>
      </HackleProvider>
    );
}
```

### Auto-collected Event Integration from WebView

{% hint style="info" %}
This feature is supported in JavaScript SDK version 11.51.0 and above.
{% endhint %}

`$page_view` and `$engagement` events occurring on websites inside WebView are disabled by default.\
You can enable each auto-collected event individually by configuring `HackleWebViewConfig` when setting up the WebView bridge.

```jsx
const hackleWebViewConfig = new HackleWebViewConfigBuilder()
  .automaticScreenTracking(true)
  .automaticEngagementTracking(true)
  .build();

const { hackleInjectedJavaScript, onHackleMessage, isHackleMessageEvent } =
  useHackleWebviewManager({
    postMessage: (message: string) => webviewRef.current?.postMessage(message),
    hackleClient,
  }, hackleWebViewConfig);
```

#### Configuration Options

<table><thead><tr><th width="213">Setting</th><th width="295">Function</th><th width="125">Default</th><th>Supported Bridge Version</th></tr></thead><tbody><tr><td><code>automaticScreenTracking</code></td><td>Whether to collect <code>$page_view</code> events occurring on the website</td><td><code>false</code></td><td>0.0.3 +</td></tr><tr><td><code>automaticEngagementTracking</code></td><td>Whether to collect <code>engagement</code> events occurring on the website</td><td><code>false</code></td><td>0.0.3 +</td></tr></tbody></table>

## JavaScript

Please complete the following tasks on the web side where the JavaScript SDK is installed.

{% hint style="info" %}
The JavaScript bridge code works as follows:

* Creates a Wrapper Client that has the same interface as the JavaScript SDK's hackleClient.
* Receives requests such as track, variation, and featureFlag occurring in the web environment and forwards them asynchronously to the React Native SDK.
* This is bridge-style code, and **the key difference from the existing hackleClient is that all methods return a Promise**.
  {% endhint %}

{% hint style="warning" %}
The bridge setup in React Native must be completed first.

* `useHackleWebviewManager` must be applied to the ReactNative WebView.
* If this is not done beforehand, the WebApp integration will not work correctly.
  {% endhint %}

{% hint style="info" %}
Github: [Full Source Code](https://github.com/hackle-io/hackle-javascript-examples/blob/main/react-native-webview-integration-js-bridge/src/index.ts)
{% endhint %}

{% tabs %}
{% tab title="esm" %}

```javascript
import{createInstance as e,DefaultBrowserPropertyProvider as t,WebViewLifecycleCompositeManager as n,Decision as r,DecisionReason as o,FeatureFlagDecision as i}from"@hackler/javascript-sdk";var s=function(e,t){return s=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},s(e,t)};function u(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}s(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return a=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var o in t=arguments[n])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e},a.apply(this,arguments)};function c(e,t,n,r){return new(n||(n=Promise))(function(o,i){function s(e){try{a(r.next(e))}catch(e){i(e)}}function u(e){try{a(r.throw(e))}catch(e){i(e)}}function a(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(s,u)}a((r=r.apply(e,t||[])).next())})}function p(e,t){var n,r,o,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},s=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return s.next=u(0),s.throw=u(1),s.return=u(2),"function"==typeof Symbol&&(s[Symbol.iterator]=function(){return this}),s;function u(u){return function(a){return function(u){if(n)throw new TypeError("Generator is already executing.");for(;s&&(s=0,u[0]&&(i=0)),i;)try{if(n=1,r&&(o=2&u[0]?r.return:u[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,u[1])).done)return o;switch(r=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return i.label++,{value:u[1],done:!1};case 5:i.label++,r=u[1],u=[0];continue;case 7:u=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){i=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){i.label=u[1];break}if(6===u[0]&&i.label<o[1]){i.label=o[1],o=u;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(u);break}o[2]&&i.ops.pop(),i.trys.pop();continue}u=t.call(e,i)}catch(e){u=[6,e],r=0}finally{n=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,a])}}}"function"==typeof SuppressedError&&SuppressedError;var f=function(){function e(){this.listeners={}}return e.prototype.on=function(e,t){this.listeners[e]=(this.listeners[e]||[]).concat(t)},e.prototype.off=function(e,t){this.listeners[e]=(this.listeners[e]||[]).filter(function(e){return e!==t})},e.prototype.emit=function(e,t){(this.listeners[e]||[]).forEach(function(e){e(t)})},e}(),l=function(){function e(e){this.parameters=e,this.parameters=e}return e.prototype.get=function(e,t){var n=this.parameters[e];return null==n?t:null==t||typeof n==typeof t?n:t},e}(),d=function(){function e(e){this.configFetcher=e,this.configFetcher=e}return e.prototype.get=function(e,t){return c(this,void 0,void 0,function(){var n,r,o,i;return p(this,function(s){switch(s.label){case 0:return s.trys.push([0,2,,3]),n=typeof t,[4,this.configFetcher(e,t,n)];case 1:if(null==(r=s.sent()))throw new Error("invoke result data not exists");switch(o=r.configValue,n){case"number":return[2,Number(o)];case"boolean":return[2,Boolean(o)];default:return[2,o]}case 2:return i=s.sent(),console.error("Unexpected exception while deciding remote config parameter[".concat(e,"]. Returning default value. : ").concat(i)),[2,t];case 3:return[2]}})})},e}(),h=function(){function e(e){this.port=e,this.cleanUp=function(){}}return e.prototype.addEventListener=function(e){window.addEventListener("message",e,!0),this.cleanUp=function(){return window.removeEventListener("message",e,!0)}},e}(),v=function(){function e(e){this.invocator=e}return e.prototype.onPageStarted=function(e,t){this.track(e,t)},e.prototype.onPageEnded=function(e,t){},e.prototype.track=function(t,n){var r,o={type:"track",payload:{event:{key:e.PAGE_VIEW_EVENT_KEY,properties:(r={},r[e.PAGE_NAME_PROPERTY_KEY]=t.pageTitle,r)}}};this.invocator.invoke(o,{onTimeout:function(){}}).catch(function(){})},e.PAGE_VIEW_EVENT_KEY="$page_view",e.PAGE_NAME_PROPERTY_KEY="$page_name",e}();const y=[];for(let e=0;e<256;++e)y.push((e+256).toString(16).slice(1));let m;const g=new Uint8Array(16);var E={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function w(e,t,n){if(E.randomUUID&&!e)return E.randomUUID();const r=(e=e||{}).random??e.rng?.()??function(){if(!m){if("undefined"==typeof crypto||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");m=crypto.getRandomValues.bind(crypto)}return m(g)}();if(r.length<16)throw new Error("Random bytes length must be >= 16");return r[6]=15&r[6]|64,r[8]=63&r[8]|128,function(e,t=0){return(y[e[t+0]]+y[e[t+1]]+y[e[t+2]]+y[e[t+3]]+"-"+y[e[t+4]]+y[e[t+5]]+"-"+y[e[t+6]]+y[e[t+7]]+"-"+y[e[t+8]]+y[e[t+9]]+"-"+y[e[t+10]]+y[e[t+11]]+y[e[t+12]]+y[e[t+13]]+y[e[t+14]]+y[e[t+15]]).toLowerCase()}(r)}var P=function(){function e(e,t,n,r){this.id=e,this.type=t,this.payload=n,this.browserProperties=r}return e.parseOrNull=function(t){try{if(e.MESSAGE_FIELD_NAME in t){var n=t[e.MESSAGE_FIELD_NAME];return new e(n.id,n.type,n.payload,n.browserProperties)}return null}catch(e){return null}},e.from=function(t,n,r,o){return new e(t,n,r,o)},e.prototype.toDto=function(){var t;return(t={})[e.MESSAGE_FIELD_NAME]={id:this.id,type:this.type,payload:this.payload,browserProperties:this.browserProperties},t},e.MESSAGE_FIELD_NAME="_hackle_message",e}();var U=function(){function e(e,t){var n=this;this.transceiver=e,this.browserPropertyProvider=t,this.pendingResolvers=new Map;this.transceiver.addEventListener(function(e){var t,r=e;if(r.data&&"undefined"!==r.data)try{var o=JSON.parse(r.data),i=P.parseOrNull(o);if(!i)return;var s=i.id,u=i.payload;null===(t=n.pendingResolvers.get(s))||void 0===t||t(u),n.pendingResolvers.delete(s)}catch(e){console.log("[DEBUG] Hackle: Failed to parse message. If message not sent by hackle, please ignore this. ".concat(e))}}),this.cleanup=function(){return n.transceiver.cleanUp()}}return e.prototype.createId=function(){return w()},e.prototype.getBrowserProperties=function(){return this.browserPropertyProvider.getBrowserProperties()},e.prototype.serialize=function(e,t,n,r){void 0===r&&(r={});var o=P.from(e,t,n,a(a({},this.getBrowserProperties()),r));return JSON.stringify(o.toDto())},e.prototype.invoke=function(e,t){var n=this,r=t.timeoutMillis,o=void 0===r?5e3:r,i=t.onTimeout,s=this.createId();return function(e,t){var n=t.timeoutMillis,r=void 0===n?5e3:n,o=t.onTimeout;return new Promise(function(t,n){e(t,n),setTimeout(function(){o(t,n)},r)})}(function(t){n.transceiver.port.postMessage(n.serialize(s,e.type,e.payload,e.browserProperties)),n.pendingResolvers.set(s,t)},{timeoutMillis:o,onTimeout:function(e){return e(i())}})},e}(),b=function(){function e(e,t){this.invocator=e,this.browserPropertyProvider=t}return e.prototype.onEngagement=function(t,n){var r,o={type:"track",payload:{event:{key:e.ENGAGEMENT_EVENT_KEY,properties:(r={},r[e.ENGAGEMENT_PAGE_NAME_KEY]=t.page.pageTitle,r[e.ENGAGEMENT_TIME_PROPERTY_KEY]=t.durationMillis,r)}},browserProperties:this.browserPropertyProvider.getBrowserProperties(t.page)};this.invocator.invoke(o,{onTimeout:function(){}}).catch(function(){})},e.ENGAGEMENT_EVENT_KEY="$engagement",e.ENGAGEMENT_TIME_PROPERTY_KEY="$engagement_time_ms",e.ENGAGEMENT_PAGE_NAME_KEY="$page_name",e}(),k={automaticScreenTracking:!1,automaticEngagementTracking:!1};function T(e,t,n,r,o){var i=function(){var e,t,n,r;try{var o=null===(t=null===(e=window._hackleApp)||void 0===e?void 0:e.getWebViewConfig)||void 0===t?void 0:t.call(e);if(!o)return k;var i=JSON.parse(o);return{automaticScreenTracking:null!==(n=i.automaticScreenTracking)&&void 0!==n?n:k.automaticScreenTracking,automaticEngagementTracking:null!==(r=i.automaticEngagementTracking)&&void 0!==r?r:k.automaticEngagementTracking}}catch(e){console.error("[DEBUG] Hackle: Failed to parse web view config. ".concat(e))}return k}(),s=new U(n,o),u=new v(s),a=new b(s,o);i.automaticScreenTracking&&r.addPageListener(u),i.automaticEngagementTracking&&r.addEngagementListener(a);var c=new N(e,t,s);return r.initialize(),c}var _=function(){function e(){this.injectFlag="_hackle_injected"}return e.prototype.isInjectedEnvironment=function(){return!("undefined"==typeof window||!window.ReactNativeWebView)&&!0===window[this.injectFlag]},e.prototype.createInstance=function(e,r){if(this.isInjectedEnvironment()){var o=new t,i=o.getBrowserProperties().browserName,s=new n("string"==typeof i?i:null);return T(e,r,new h(window.ReactNativeWebView),s,o)}return new I(e,r)},e}(),N=function(e){function t(t,n,r){var o=e.call(this)||this;return o.sdkKey=t,o.config=n,o.messenger=r,o}return u(t,e),t.prototype.onInitialized=function(e){return Promise.resolve({success:!0})},t.prototype.getSessionId=function(){return c(this,void 0,void 0,function(){return p(this,function(e){switch(e.label){case 0:return[4,this.messenger.invoke({type:"getSessionId",payload:null},{onTimeout:function(){return{sessionId:""}}})];case 1:return[2,e.sent().sessionId]}})})},t.prototype.getUser=function(){return c(this,void 0,void 0,function(){return p(this,function(e){switch(e.label){case 0:return[4,this.messenger.invoke({type:"getUser",payload:null},{onTimeout:function(){return{user:{}}}})];case 1:return[2,e.sent().user]}})})},t.prototype.emitUserUpdated=function(){this.emit("user-updated",JSON.stringify(this.getUser()))},t.prototype.setUser=function(e){return c(this,void 0,void 0,function(){var t=this;return p(this,function(n){return[2,this.messenger.invoke({type:"setUser",payload:{user:e}},{onTimeout:function(){}}).then(function(){t.emitUserUpdated()})]})})},t.prototype.setUserId=function(e){return c(this,void 0,void 0,function(){var t,n=this;return p(this,function(r){return t=e,null==e&&(t=null),[2,this.messenger.invoke({type:"setUserId",payload:{userId:t}},{onTimeout:function(){}}).then(function(){n.emitUserUpdated()})]})})},t.prototype.setDeviceId=function(e){return c(this,void 0,void 0,function(){var t=this;return p(this,function(n){return[2,this.messenger.invoke({type:"setDeviceId",payload:{deviceId:e}},{onTimeout:function(){}}).then(function(){t.emitUserUpdated()})]})})},t.prototype.setUserProperty=function(e,t){return c(this,void 0,void 0,function(){var n=this;return p(this,function(r){return[2,this.messenger.invoke({type:"setUserProperty",payload:{key:e,value:t}},{onTimeout:function(){}}).then(function(){n.emitUserUpdated()})]})})},t.prototype.setUserProperties=function(e){return c(this,void 0,void 0,function(){var t=this;return p(this,function(n){return[2,this.messenger.invoke({type:"setUserProperties",payload:{properties:e}},{onTimeout:function(){}}).then(function(){t.emitUserUpdated()})]})})},t.prototype.updateUserProperties=function(e){return c(this,void 0,void 0,function(){var t=this;return p(this,function(n){return[2,this.messenger.invoke({type:"updateUserProperties",payload:{operations:e.toRecord()}},{onTimeout:function(){}}).then(function(){t.emitUserUpdated()})]})})},t.prototype.updatePushSubscriptions=function(e){return this.messenger.invoke({type:"updatePushSubscriptions",payload:{operations:e.toRecord()}},{onTimeout:function(){}})},t.prototype.updateSmsSubscriptions=function(e){return this.messenger.invoke({type:"updateSmsSubscriptions",payload:{operations:e.toRecord()}},{onTimeout:function(){}})},t.prototype.updateKakaoSubscriptions=function(e){return this.messenger.invoke({type:"updateKakaoSubscriptions",payload:{operations:e.toRecord()}},{onTimeout:function(){}})},t.prototype.setPhoneNumber=function(e){return this.messenger.invoke({type:"setPhoneNumber",payload:{phoneNumber:e}},{onTimeout:function(){}})},t.prototype.unsetPhoneNumber=function(){return this.messenger.invoke({type:"unsetPhoneNumber",payload:null},{onTimeout:function(){}})},t.prototype.resetUser=function(){return c(this,void 0,void 0,function(){var e=this;return p(this,function(t){return[2,this.messenger.invoke({type:"resetUser",payload:null},{onTimeout:function(){}}).then(function(){e.emitUserUpdated()})]})})},t.prototype.variation=function(e){return c(this,void 0,void 0,function(){return p(this,function(t){switch(t.label){case 0:return[4,this.messenger.invoke({type:"variation",payload:{experimentKey:e}},{onTimeout:function(){return{variation:"A"}}})];case 1:return[2,t.sent().variation]}})})},t.prototype.variationDetail=function(e){return c(this,void 0,void 0,function(){var t,n,i,s;return p(this,function(u){switch(u.label){case 0:return u.trys.push([0,2,,3]),[4,this.messenger.invoke({type:"variationDetail",payload:{experimentKey:e}},{onTimeout:function(){throw new Error("timeout")}})];case 1:return t=u.sent(),n=t.variation,i=t.reason,s=t.parameters,[2,r.of(n,i,new l(null!=s?s:{}))];case 2:return u.sent(),[2,r.of("A",o.EXCEPTION)];case 3:return[2]}})})},t.prototype.isFeatureOn=function(e){return c(this,void 0,void 0,function(){return p(this,function(t){switch(t.label){case 0:return[4,this.messenger.invoke({type:"isFeatureOn",payload:{featureKey:e}},{onTimeout:function(){return{isOn:!1}}})];case 1:return[2,t.sent().isOn]}})})},t.prototype.featureFlagDetail=function(e){return c(this,void 0,void 0,function(){var t,n,r,s;return p(this,function(u){switch(u.label){case 0:return u.trys.push([0,2,,3]),[4,this.messenger.invoke({type:"featureFlagDetail",payload:{featureKey:e}},{onTimeout:function(){throw new Error("timeout")}})];case 1:return t=u.sent(),n=t.isOn,r=t.reason,s=t.parameters,[2,new i(n,r,new l(null!=s?s:{}),void 0)];case 2:return u.sent(),[2,i.off(o.EXCEPTION)];case 3:return[2]}})})},t.prototype.track=function(e){return this.messenger.invoke({type:"track",payload:{event:e}},{onTimeout:function(){}})},t.prototype.trackPageView=function(){return c(this,void 0,void 0,function(){return p(this,function(e){return[2]})})},t.prototype.remoteConfig=function(){var e=this;return new d(function(t,n,r){return e.messenger.invoke({type:"remoteConfig",payload:{key:t,defaultValue:n,valueType:r}},{onTimeout:function(){return n}})})},t.prototype.showUserExplorer=function(){return this.messenger.invoke({type:"showUserExplorer",payload:null},{onTimeout:function(){}})},t.prototype.hideUserExplorer=function(){return c(this,void 0,void 0,function(){return p(this,function(e){return[2,this.messenger.invoke({type:"hideUserExplorer",payload:null},{onTimeout:function(){}})]})})},t.prototype.fetch=function(){return this.messenger.invoke({type:"fetch",payload:null},{onTimeout:function(){}})},t.prototype.getDisplayedInAppMessage=function(){return console.log("[DEBUG] Hackle: getDisplayedInAppMessage is not supported in React Native WebView environment."),Promise.resolve(null)},t}(f),I=function(t){function n(n,r){var o=t.call(this)||this;return o.client=e(n,r),o}return u(n,t),n.prototype.emitUserUpdated=function(){this.emit("user-updated",JSON.stringify(this.getUser()))},n.prototype.getSessionId=function(){return Promise.resolve(this.client.getSessionId())},n.prototype.getUser=function(){return Promise.resolve(this.client.getUser())},n.prototype.setUser=function(e){return c(this,void 0,void 0,function(){var t=this;return p(this,function(n){return[2,Promise.resolve(this.client.setUser(e)).then(function(){t.emitUserUpdated()})]})})},n.prototype.setUserId=function(e){return c(this,void 0,void 0,function(){var t=this;return p(this,function(n){return[2,Promise.resolve(this.client.setUserId(e)).then(function(){t.emitUserUpdated()})]})})},n.prototype.setDeviceId=function(e){return c(this,void 0,void 0,function(){var t=this;return p(this,function(n){return[2,Promise.resolve(this.client.setDeviceId(e)).then(function(){t.emitUserUpdated()})]})})},n.prototype.setUserProperty=function(e,t){return c(this,void 0,void 0,function(){var n=this;return p(this,function(r){return[2,Promise.resolve(this.client.setUserProperty(e,t)).then(function(){n.emitUserUpdated()})]})})},n.prototype.setUserProperties=function(e){return c(this,void 0,void 0,function(){var t=this;return p(this,function(n){return[2,Promise.resolve(this.client.setUserProperties(e)).then(function(){t.emitUserUpdated()})]})})},n.prototype.updateUserProperties=function(e){return c(this,void 0,void 0,function(){var t=this;return p(this,function(n){return[2,Promise.resolve(this.client.updateUserProperties(e)).then(function(){t.emitUserUpdated()})]})})},n.prototype.updatePushSubscriptions=function(e){return Promise.resolve(this.client.updatePushSubscriptions(e))},n.prototype.updateSmsSubscriptions=function(e){return Promise.resolve(this.client.updateSmsSubscriptions(e))},n.prototype.updateKakaoSubscriptions=function(e){return Promise.resolve(this.client.updateKakaoSubscriptions(e))},n.prototype.setPhoneNumber=function(e){return Promise.resolve(this.client.setPhoneNumber(e))},n.prototype.unsetPhoneNumber=function(){return Promise.resolve(this.client.unsetPhoneNumber())},n.prototype.resetUser=function(){return c(this,void 0,void 0,function(){var e=this;return p(this,function(t){return[2,Promise.resolve(this.client.resetUser()).then(function(){e.emitUserUpdated()})]})})},n.prototype.variation=function(e){return Promise.resolve(this.client.variation(e))},n.prototype.variationDetail=function(e){return Promise.resolve(this.client.variationDetail(e))},n.prototype.isFeatureOn=function(e){return Promise.resolve(this.client.isFeatureOn(e))},n.prototype.featureFlagDetail=function(e){return Promise.resolve(this.client.featureFlagDetail(e))},n.prototype.track=function(e){return Promise.resolve(this.client.track(e))},n.prototype.trackPageView=function(e){return Promise.resolve(this.client.trackPageView(e))},n.prototype.remoteConfig=function(){var e=this;return new d(function(t,n,r){var o=e.client.remoteConfig().get(t,n);return Promise.resolve({configValue:o})})},n.prototype.showUserExplorer=function(){return Promise.resolve(this.client.showUserExplorer())},n.prototype.hideUserExplorer=function(){return Promise.resolve(this.client.hideUserExplorer())},n.prototype.fetch=function(){return Promise.resolve(this.client.fetch())},n.prototype.onInitialized=function(e){return this.client.onInitialized(e)},n.prototype.getDisplayedInAppMessage=function(){return Promise.resolve(this.client.getDisplayedInAppMessageView())},n}(f);export{_ as default};
```

{% endtab %}

{% tab title="umd" %}

```javascript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@hackler/javascript-sdk")):"function"==typeof define&&define.amd?define(["@hackler/javascript-sdk"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).HackleManager=t(e.Hackle)}(this,function(e){"use strict";var t=function(e,n){return t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},t(e,n)};function n(e,n){if("function"!=typeof n&&null!==n)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");function r(){this.constructor=e}t(e,n),e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}var r=function(){return r=Object.assign||function(e){for(var t,n=1,r=arguments.length;n<r;n++)for(var o in t=arguments[n])Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o]);return e},r.apply(this,arguments)};function o(e,t,n,r){return new(n||(n=Promise))(function(o,i){function s(e){try{a(r.next(e))}catch(e){i(e)}}function u(e){try{a(r.throw(e))}catch(e){i(e)}}function a(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(s,u)}a((r=r.apply(e,t||[])).next())})}function i(e,t){var n,r,o,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},s=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return s.next=u(0),s.throw=u(1),s.return=u(2),"function"==typeof Symbol&&(s[Symbol.iterator]=function(){return this}),s;function u(u){return function(a){return function(u){if(n)throw new TypeError("Generator is already executing.");for(;s&&(s=0,u[0]&&(i=0)),i;)try{if(n=1,r&&(o=2&u[0]?r.return:u[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,u[1])).done)return o;switch(r=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return i.label++,{value:u[1],done:!1};case 5:i.label++,r=u[1],u=[0];continue;case 7:u=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==u[0]&&2!==u[0])){i=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){i.label=u[1];break}if(6===u[0]&&i.label<o[1]){i.label=o[1],o=u;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(u);break}o[2]&&i.ops.pop(),i.trys.pop();continue}u=t.call(e,i)}catch(e){u=[6,e],r=0}finally{n=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,a])}}}"function"==typeof SuppressedError&&SuppressedError;var s=function(){function e(){this.listeners={}}return e.prototype.on=function(e,t){this.listeners[e]=(this.listeners[e]||[]).concat(t)},e.prototype.off=function(e,t){this.listeners[e]=(this.listeners[e]||[]).filter(function(e){return e!==t})},e.prototype.emit=function(e,t){(this.listeners[e]||[]).forEach(function(e){e(t)})},e}(),u=function(){function e(e){this.parameters=e,this.parameters=e}return e.prototype.get=function(e,t){var n=this.parameters[e];return null==n?t:null==t||typeof n==typeof t?n:t},e}(),a=function(){function e(e){this.configFetcher=e,this.configFetcher=e}return e.prototype.get=function(e,t){return o(this,void 0,void 0,function(){var n,r,o,s;return i(this,function(i){switch(i.label){case 0:return i.trys.push([0,2,,3]),n=typeof t,[4,this.configFetcher(e,t,n)];case 1:if(null==(r=i.sent()))throw new Error("invoke result data not exists");switch(o=r.configValue,n){case"number":return[2,Number(o)];case"boolean":return[2,Boolean(o)];default:return[2,o]}case 2:return s=i.sent(),console.error("Unexpected exception while deciding remote config parameter[".concat(e,"]. Returning default value. : ").concat(s)),[2,t];case 3:return[2]}})})},e}(),c=function(){function e(e){this.port=e,this.cleanUp=function(){}}return e.prototype.addEventListener=function(e){window.addEventListener("message",e,!0),this.cleanUp=function(){return window.removeEventListener("message",e,!0)}},e}(),p=function(){function e(e){this.invocator=e}return e.prototype.onPageStarted=function(e,t){this.track(e,t)},e.prototype.onPageEnded=function(e,t){},e.prototype.track=function(t,n){var r,o={type:"track",payload:{event:{key:e.PAGE_VIEW_EVENT_KEY,properties:(r={},r[e.PAGE_NAME_PROPERTY_KEY]=t.pageTitle,r)}}};this.invocator.invoke(o,{onTimeout:function(){}}).catch(function(){})},e.PAGE_VIEW_EVENT_KEY="$page_view",e.PAGE_NAME_PROPERTY_KEY="$page_name",e}();const f=[];for(let e=0;e<256;++e)f.push((e+256).toString(16).slice(1));let l;const d=new Uint8Array(16);var h={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function v(e,t,n){if(h.randomUUID&&!e)return h.randomUUID();const r=(e=e||{}).random??e.rng?.()??function(){if(!l){if("undefined"==typeof crypto||!crypto.getRandomValues)throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");l=crypto.getRandomValues.bind(crypto)}return l(d)}();if(r.length<16)throw new Error("Random bytes length must be >= 16");return r[6]=15&r[6]|64,r[8]=63&r[8]|128,function(e,t=0){return(f[e[t+0]]+f[e[t+1]]+f[e[t+2]]+f[e[t+3]]+"-"+f[e[t+4]]+f[e[t+5]]+"-"+f[e[t+6]]+f[e[t+7]]+"-"+f[e[t+8]]+f[e[t+9]]+"-"+f[e[t+10]]+f[e[t+11]]+f[e[t+12]]+f[e[t+13]]+f[e[t+14]]+f[e[t+15]]).toLowerCase()}(r)}var y=function(){function e(e,t,n,r){this.id=e,this.type=t,this.payload=n,this.browserProperties=r}return e.parseOrNull=function(t){try{if(e.MESSAGE_FIELD_NAME in t){var n=t[e.MESSAGE_FIELD_NAME];return new e(n.id,n.type,n.payload,n.browserProperties)}return null}catch(e){return null}},e.from=function(t,n,r,o){return new e(t,n,r,o)},e.prototype.toDto=function(){var t;return(t={})[e.MESSAGE_FIELD_NAME]={id:this.id,type:this.type,payload:this.payload,browserProperties:this.browserProperties},t},e.MESSAGE_FIELD_NAME="_hackle_message",e}();var m=function(){function e(e,t){var n=this;this.transceiver=e,this.browserPropertyProvider=t,this.pendingResolvers=new Map;this.transceiver.addEventListener(function(e){var t,r=e;if(r.data&&"undefined"!==r.data)try{var o=JSON.parse(r.data),i=y.parseOrNull(o);if(!i)return;var s=i.id,u=i.payload;null===(t=n.pendingResolvers.get(s))||void 0===t||t(u),n.pendingResolvers.delete(s)}catch(e){console.log("[DEBUG] Hackle: Failed to parse message. If message not sent by hackle, please ignore this. ".concat(e))}}),this.cleanup=function(){return n.transceiver.cleanUp()}}return e.prototype.createId=function(){return v()},e.prototype.getBrowserProperties=function(){return this.browserPropertyProvider.getBrowserProperties()},e.prototype.serialize=function(e,t,n,o){void 0===o&&(o={});var i=y.from(e,t,n,r(r({},this.getBrowserProperties()),o));return JSON.stringify(i.toDto())},e.prototype.invoke=function(e,t){var n=this,r=t.timeoutMillis,o=void 0===r?5e3:r,i=t.onTimeout,s=this.createId();return function(e,t){var n=t.timeoutMillis,r=void 0===n?5e3:n,o=t.onTimeout;return new Promise(function(t,n){e(t,n),setTimeout(function(){o(t,n)},r)})}(function(t){n.transceiver.port.postMessage(n.serialize(s,e.type,e.payload,e.browserProperties)),n.pendingResolvers.set(s,t)},{timeoutMillis:o,onTimeout:function(e){return e(i())}})},e}(),g=function(){function e(e,t){this.invocator=e,this.browserPropertyProvider=t}return e.prototype.onEngagement=function(t,n){var r,o={type:"track",payload:{event:{key:e.ENGAGEMENT_EVENT_KEY,properties:(r={},r[e.ENGAGEMENT_PAGE_NAME_KEY]=t.page.pageTitle,r[e.ENGAGEMENT_TIME_PROPERTY_KEY]=t.durationMillis,r)}},browserProperties:this.browserPropertyProvider.getBrowserProperties(t.page)};this.invocator.invoke(o,{onTimeout:function(){}}).catch(function(){})},e.ENGAGEMENT_EVENT_KEY="$engagement",e.ENGAGEMENT_TIME_PROPERTY_KEY="$engagement_time_ms",e.ENGAGEMENT_PAGE_NAME_KEY="$page_name",e}(),E={automaticScreenTracking:!1,automaticEngagementTracking:!1};function w(e,t,n,r,o){var i=function(){var e,t,n,r;try{var o=null===(t=null===(e=window._hackleApp)||void 0===e?void 0:e.getWebViewConfig)||void 0===t?void 0:t.call(e);if(!o)return E;var i=JSON.parse(o);return{automaticScreenTracking:null!==(n=i.automaticScreenTracking)&&void 0!==n?n:E.automaticScreenTracking,automaticEngagementTracking:null!==(r=i.automaticEngagementTracking)&&void 0!==r?r:E.automaticEngagementTracking}}catch(e){console.error("[DEBUG] Hackle: Failed to parse web view config. ".concat(e))}return E}(),s=new m(n,o),u=new p(s),a=new g(s,o);i.automaticScreenTracking&&r.addPageListener(u),i.automaticEngagementTracking&&r.addEngagementListener(a);var c=new U(e,t,s);return r.initialize(),c}var P=function(){function t(){this.injectFlag="_hackle_injected"}return t.prototype.isInjectedEnvironment=function(){return!("undefined"==typeof window||!window.ReactNativeWebView)&&!0===window[this.injectFlag]},t.prototype.createInstance=function(t,n){if(this.isInjectedEnvironment()){var r=new e.DefaultBrowserPropertyProvider,o=r.getBrowserProperties().browserName,i=new e.WebViewLifecycleCompositeManager("string"==typeof o?o:null);return w(t,n,new c(window.ReactNativeWebView),i,r)}return new b(t,n)},t}(),U=function(t){function r(e,n,r){var o=t.call(this)||this;return o.sdkKey=e,o.config=n,o.messenger=r,o}return n(r,t),r.prototype.onInitialized=function(e){return Promise.resolve({success:!0})},r.prototype.getSessionId=function(){return o(this,void 0,void 0,function(){return i(this,function(e){switch(e.label){case 0:return[4,this.messenger.invoke({type:"getSessionId",payload:null},{onTimeout:function(){return{sessionId:""}}})];case 1:return[2,e.sent().sessionId]}})})},r.prototype.getUser=function(){return o(this,void 0,void 0,function(){return i(this,function(e){switch(e.label){case 0:return[4,this.messenger.invoke({type:"getUser",payload:null},{onTimeout:function(){return{user:{}}}})];case 1:return[2,e.sent().user]}})})},r.prototype.emitUserUpdated=function(){this.emit("user-updated",JSON.stringify(this.getUser()))},r.prototype.setUser=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(n){return[2,this.messenger.invoke({type:"setUser",payload:{user:e}},{onTimeout:function(){}}).then(function(){t.emitUserUpdated()})]})})},r.prototype.setUserId=function(e){return o(this,void 0,void 0,function(){var t,n=this;return i(this,function(r){return t=e,null==e&&(t=null),[2,this.messenger.invoke({type:"setUserId",payload:{userId:t}},{onTimeout:function(){}}).then(function(){n.emitUserUpdated()})]})})},r.prototype.setDeviceId=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(n){return[2,this.messenger.invoke({type:"setDeviceId",payload:{deviceId:e}},{onTimeout:function(){}}).then(function(){t.emitUserUpdated()})]})})},r.prototype.setUserProperty=function(e,t){return o(this,void 0,void 0,function(){var n=this;return i(this,function(r){return[2,this.messenger.invoke({type:"setUserProperty",payload:{key:e,value:t}},{onTimeout:function(){}}).then(function(){n.emitUserUpdated()})]})})},r.prototype.setUserProperties=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(n){return[2,this.messenger.invoke({type:"setUserProperties",payload:{properties:e}},{onTimeout:function(){}}).then(function(){t.emitUserUpdated()})]})})},r.prototype.updateUserProperties=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(n){return[2,this.messenger.invoke({type:"updateUserProperties",payload:{operations:e.toRecord()}},{onTimeout:function(){}}).then(function(){t.emitUserUpdated()})]})})},r.prototype.updatePushSubscriptions=function(e){return this.messenger.invoke({type:"updatePushSubscriptions",payload:{operations:e.toRecord()}},{onTimeout:function(){}})},r.prototype.updateSmsSubscriptions=function(e){return this.messenger.invoke({type:"updateSmsSubscriptions",payload:{operations:e.toRecord()}},{onTimeout:function(){}})},r.prototype.updateKakaoSubscriptions=function(e){return this.messenger.invoke({type:"updateKakaoSubscriptions",payload:{operations:e.toRecord()}},{onTimeout:function(){}})},r.prototype.setPhoneNumber=function(e){return this.messenger.invoke({type:"setPhoneNumber",payload:{phoneNumber:e}},{onTimeout:function(){}})},r.prototype.unsetPhoneNumber=function(){return this.messenger.invoke({type:"unsetPhoneNumber",payload:null},{onTimeout:function(){}})},r.prototype.resetUser=function(){return o(this,void 0,void 0,function(){var e=this;return i(this,function(t){return[2,this.messenger.invoke({type:"resetUser",payload:null},{onTimeout:function(){}}).then(function(){e.emitUserUpdated()})]})})},r.prototype.variation=function(e){return o(this,void 0,void 0,function(){return i(this,function(t){switch(t.label){case 0:return[4,this.messenger.invoke({type:"variation",payload:{experimentKey:e}},{onTimeout:function(){return{variation:"A"}}})];case 1:return[2,t.sent().variation]}})})},r.prototype.variationDetail=function(t){return o(this,void 0,void 0,function(){var n,r,o,s;return i(this,function(i){switch(i.label){case 0:return i.trys.push([0,2,,3]),[4,this.messenger.invoke({type:"variationDetail",payload:{experimentKey:t}},{onTimeout:function(){throw new Error("timeout")}})];case 1:return n=i.sent(),r=n.variation,o=n.reason,s=n.parameters,[2,e.Decision.of(r,o,new u(null!=s?s:{}))];case 2:return i.sent(),[2,e.Decision.of("A",e.DecisionReason.EXCEPTION)];case 3:return[2]}})})},r.prototype.isFeatureOn=function(e){return o(this,void 0,void 0,function(){return i(this,function(t){switch(t.label){case 0:return[4,this.messenger.invoke({type:"isFeatureOn",payload:{featureKey:e}},{onTimeout:function(){return{isOn:!1}}})];case 1:return[2,t.sent().isOn]}})})},r.prototype.featureFlagDetail=function(t){return o(this,void 0,void 0,function(){var n,r,o,s;return i(this,function(i){switch(i.label){case 0:return i.trys.push([0,2,,3]),[4,this.messenger.invoke({type:"featureFlagDetail",payload:{featureKey:t}},{onTimeout:function(){throw new Error("timeout")}})];case 1:return n=i.sent(),r=n.isOn,o=n.reason,s=n.parameters,[2,new e.FeatureFlagDecision(r,o,new u(null!=s?s:{}),void 0)];case 2:return i.sent(),[2,e.FeatureFlagDecision.off(e.DecisionReason.EXCEPTION)];case 3:return[2]}})})},r.prototype.track=function(e){return this.messenger.invoke({type:"track",payload:{event:e}},{onTimeout:function(){}})},r.prototype.trackPageView=function(){return o(this,void 0,void 0,function(){return i(this,function(e){return[2]})})},r.prototype.remoteConfig=function(){var e=this;return new a(function(t,n,r){return e.messenger.invoke({type:"remoteConfig",payload:{key:t,defaultValue:n,valueType:r}},{onTimeout:function(){return n}})})},r.prototype.showUserExplorer=function(){return this.messenger.invoke({type:"showUserExplorer",payload:null},{onTimeout:function(){}})},r.prototype.hideUserExplorer=function(){return o(this,void 0,void 0,function(){return i(this,function(e){return[2,this.messenger.invoke({type:"hideUserExplorer",payload:null},{onTimeout:function(){}})]})})},r.prototype.fetch=function(){return this.messenger.invoke({type:"fetch",payload:null},{onTimeout:function(){}})},r.prototype.getDisplayedInAppMessage=function(){return console.log("[DEBUG] Hackle: getDisplayedInAppMessage is not supported in React Native WebView environment."),Promise.resolve(null)},r}(s),b=function(t){function r(n,r){var o=t.call(this)||this;return o.client=e.createInstance(n,r),o}return n(r,t),r.prototype.emitUserUpdated=function(){this.emit("user-updated",JSON.stringify(this.getUser()))},r.prototype.getSessionId=function(){return Promise.resolve(this.client.getSessionId())},r.prototype.getUser=function(){return Promise.resolve(this.client.getUser())},r.prototype.setUser=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(n){return[2,Promise.resolve(this.client.setUser(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.setUserId=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(n){return[2,Promise.resolve(this.client.setUserId(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.setDeviceId=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(n){return[2,Promise.resolve(this.client.setDeviceId(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.setUserProperty=function(e,t){return o(this,void 0,void 0,function(){var n=this;return i(this,function(r){return[2,Promise.resolve(this.client.setUserProperty(e,t)).then(function(){n.emitUserUpdated()})]})})},r.prototype.setUserProperties=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(n){return[2,Promise.resolve(this.client.setUserProperties(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.updateUserProperties=function(e){return o(this,void 0,void 0,function(){var t=this;return i(this,function(n){return[2,Promise.resolve(this.client.updateUserProperties(e)).then(function(){t.emitUserUpdated()})]})})},r.prototype.updatePushSubscriptions=function(e){return Promise.resolve(this.client.updatePushSubscriptions(e))},r.prototype.updateSmsSubscriptions=function(e){return Promise.resolve(this.client.updateSmsSubscriptions(e))},r.prototype.updateKakaoSubscriptions=function(e){return Promise.resolve(this.client.updateKakaoSubscriptions(e))},r.prototype.setPhoneNumber=function(e){return Promise.resolve(this.client.setPhoneNumber(e))},r.prototype.unsetPhoneNumber=function(){return Promise.resolve(this.client.unsetPhoneNumber())},r.prototype.resetUser=function(){return o(this,void 0,void 0,function(){var e=this;return i(this,function(t){return[2,Promise.resolve(this.client.resetUser()).then(function(){e.emitUserUpdated()})]})})},r.prototype.variation=function(e){return Promise.resolve(this.client.variation(e))},r.prototype.variationDetail=function(e){return Promise.resolve(this.client.variationDetail(e))},r.prototype.isFeatureOn=function(e){return Promise.resolve(this.client.isFeatureOn(e))},r.prototype.featureFlagDetail=function(e){return Promise.resolve(this.client.featureFlagDetail(e))},r.prototype.track=function(e){return Promise.resolve(this.client.track(e))},r.prototype.trackPageView=function(e){return Promise.resolve(this.client.trackPageView(e))},r.prototype.remoteConfig=function(){var e=this;return new a(function(t,n,r){var o=e.client.remoteConfig().get(t,n);return Promise.resolve({configValue:o})})},r.prototype.showUserExplorer=function(){return Promise.resolve(this.client.showUserExplorer())},r.prototype.hideUserExplorer=function(){return Promise.resolve(this.client.hideUserExplorer())},r.prototype.fetch=function(){return Promise.resolve(this.client.fetch())},r.prototype.onInitialized=function(e){return this.client.onInitialized(e)},r.prototype.getDisplayedInAppMessage=function(){return Promise.resolve(this.client.getDisplayedInAppMessageView())},r}(s);return P});
```

{% endtab %}
{% endtabs %}

Add the source code above to your project.

* esm is recommended. The module is provided as a `default export`.
* If you cannot use modules, use umd instead.
  * The module is provided in the global scope under the name `HackleManager`.

### Source Code Integration

{% hint style="info" %}
The source code is not provided as an npm package.
{% endhint %}

For more detailed integration instructions beyond the step-by-step guide below, please refer to the examples in the repository below.

* [github](https://github.com/hackle-io/hackle-javascript-examples/tree/main/react-native-webview-nextjs-integration/lib/hackle)

#### TypeScript Support

Building `react-native-webview-integration-js-bridge` from [github](https://github.com/hackle-io/hackle-javascript-examples/tree/main/react-native-webview-nextjs-integration/lib/hackle) will emit type declaration files (d.ts).

{% hint style="info" %}
Please refer to `react-native-webview-nextjs-integration`.

It provides an example of referencing file dependencies using the `lib` directory.
{% endhint %}

#### Creating an Instance

You can create an instance by calling `createInstance` as shown below.

{% hint style="info" %}
Please fill in the import path according to your installation environment.
{% endhint %}

* Export the created instance for use.

```typescript
import HackleManager from "./web-view-integration";

const manager = new HackleManager();
const hackleClient = manager.createInstance(process.env.NEXT_PUBLIC_HACKLE_SDK_KEY!, {
  // debug log toggle
  debug: true
});

export default hackleClient;

```

#### Calling Methods

{% hint style="info" %}
Be aware that the return type of all methods is Promise.
{% endhint %}

For the types of supported methods, please refer to the JavaScript/ReactNative SDK documentation.

```typescript
import hackleClient from './client';

async function getVariation() {
  const variation = await hackleClient.variation(42);
  if (variation === 'A') {
    // if variation is A do something...
  } else {
    // else
  }
}
```

### Are you using React/Vue/Next.js?

{% hint style="danger" %}
react-sdk is not supported in the React Native WebView WebApp integration environment.

react-sdk cannot be used as-is in the React Native WebView environment.
{% endhint %}

If you are using libraries/frameworks such as Vue, React, or Next.js inside React Native WebView, please refer to the guide below.

**Examples**

* Vue: [Example](https://github.com/hackle-io/hackle-javascript-examples/tree/main/react-native-webview-%08vue-integration)
* React: [Example](https://github.com/hackle-io/hackle-javascript-examples/tree/main/react-native-webview-react-integration)
* Next.js: [Example](https://github.com/hackle-io/hackle-javascript-examples/tree/main/react-native-webview-nextjs-integration)

#### React

**You can create and use hooks similar to the Custom hooks of the existing react-sdk.**

Refer to the hooks included in the Example and write the hooks you need.

{% hint style="info" %}
Why do I need to handle Loading?

Although the message send/receive latency is not long, it is recommended to implement loading handling.

* This is to prevent users from seeing a different screen from what they initially saw after the experiment (variation) result is received.
  {% endhint %}

{% hint style="info" %}
Github: [Source](https://github.com/hackle-io/hackle-javascript-examples/blob/main/react-native-webview-react-integration/src/App.tsx)
{% endhint %}

```jsx
import useVariation from "../hooks/useVariation";

interface VariationTesterProps {}

export default function VariationTester({}: VariationTesterProps) {
  const { data: variation } = useVariation(40, "A");

  return <pre style={{ fontSize: 54 }}>{variation}</pre>;
}
```

```jsx
import useFeature from "../hooks/useFeature";

interface FeatureTesterProps {}

export default function FeatureTester({}: FeatureTesterProps) {
  const { data: isOn } = useFeature(40, false);

  return <pre style={{ fontSize: 54 }}>{isOn ? "On" : "Off"}</pre>;
}
```

```jsx
import useRemoteConfig from "../hooks/useRemoteConfig";

export default function RemoteConfig() {
  const { config } = useRemoteConfig(
    "targeting_rule_test",
    "String 타입의 기본 값",
  );

  return (
    <pre style={{ fontSize: 54, height: 400, backgroundColor: "#75be6b" }}>
      {config}
    </pre>
  );
}
```

```jsx
import hackleClient from "./modules/client";

export default function CustomTracker() {
  return (
    <div>
      <button
        onClick={() =>
          hackleClient.track({
            key: "click_button",
            properties: {
              button_name: "custom",
            },
          })
        }>
        Track Custom Event
      </button>
    </div>
  );
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.hackle.io/en/development-guide/react-native/webapp-integration/react-native-web-app-intergration-deprecated.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
