Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1947,6 +1947,7 @@ type Options = {
enableUnknownActivation: boolean;
isEuIterableService: boolean;
dangerouslyAllowJsPopups: boolean;
allowIframeScripts: boolean;
eventThresholdLimit?: number;
onUnknownUserCreated?: (userId: string) => void;
identityResolution?: {
Expand Down Expand Up @@ -2698,6 +2699,43 @@ For more information, see:
- [MDN docs for `allow-popups-to-escape-sandbox`](https://developer.mozilla.org/docs/Web/HTML/Element/iframe#allow-popups-to-escape-sandbox)
- [Can I Use? `allow-popups-to-escape-sandbox`](https://caniuse.com/mdn-html_elements_iframe_sandbox_allow-popups-to-escape-sandbox)

### Safari: Enabling full in-app message functionality

By default, Safari blocks JavaScript execution inside the sandboxed `iframe`
used to display in-app messages. This prevents click tracking, `action://`
link support, and proper close button behavior in Safari.

To enable full functionality in Safari, set `allowIframeScripts` to `true`
in the configuration options. This adds `allow-scripts` to the iframe sandbox
attribute, allowing Safari to execute JavaScript event handlers inside the
iframe just like Chrome and Firefox.

```ts
import { initializeWithConfig } from '@iterable/web-sdk';

const { clearRefresh, setEmail, setUserID, logout } = initializeWithConfig({
authToken: '<<YOUR_API_KEY>>',
configOptions: {
allowIframeScripts: true,
},
generateJWT: ({ email, userID }) =>
yourAsyncJWTGeneratorMethod({ email, userID }).then(
({ jwt_token }) => jwt_token
)
});
```

When this option is enabled:

- **Click tracking** works in Safari (previously not tracked)
- **`action://` links** work in Safari (previously non-functional)
- **Close buttons** render inside the iframe as expected
- **`isRequiredToDismissMessage`** is properly honored in Safari

Since in-app message content is authored by you through the Iterable platform,
the security risk of enabling scripts is minimal. However, if your messages
include user-generated content, evaluate the risk before enabling this option.

# TypeScript

Iterable's Web SDK includes TypeScript definitions. All SDK methods should be
Expand Down
7 changes: 6 additions & 1 deletion src/inapp/inapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
trackInAppOpen
} from '../events/inapp/events';
import { IterablePromise } from '../types';
import { config } from '../utils/config';
import { requestMessages } from './request';
import {
DisplayOptions,
Expand Down Expand Up @@ -274,8 +275,12 @@ export function getInAppMessages(
}

const ua = navigator.userAgent;
const isSafari =
const isSafariUA =
!!ua.match(/safari/i) && !ua.match(/chrome|chromium|crios/i);
// When allowIframeScripts is enabled, Safari can execute JS in iframes
// so we don't need the Safari-specific workarounds
const isSafari =
isSafariUA && !config.getConfig('allowIframeScripts');

/**
* We allow users to dismiss messages by clicking outside of the
Expand Down
4 changes: 3 additions & 1 deletion src/inapp/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,13 +288,15 @@ const generateSecuredIFrame = () => {
iframe.setAttribute('id', 'iterable-iframe');
// allow-popups and allow-top-navigation is to enable links for Safari since the iframe will block
// event handlers on elements in it preventing our custom link handling
// allow-scripts is optionally enabled via allowIframeScripts config to support
// click tracking and action:// links in Safari
iframe.setAttribute(
'sandbox',
`allow-same-origin allow-popups allow-top-navigation ${
config.getConfig('dangerouslyAllowJsPopups')
? 'allow-popups-to-escape-sandbox'
: ''
}`
} ${config.getConfig('allowIframeScripts') ? 'allow-scripts' : ''}`.trim()
);
/*
_display: none_ would remove the ability to set event handlers on elements
Expand Down
2 changes: 2 additions & 0 deletions src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type Options = {
enableUnknownActivation: boolean;
isEuIterableService: boolean;
dangerouslyAllowJsPopups: boolean;
allowIframeScripts: boolean;
eventThresholdLimit?: number;
onUnknownUserCreated?: (userId: string) => void;
identityResolution?: IdentityResolution;
Expand All @@ -23,6 +24,7 @@ const _config = () => {
enableUnknownActivation: false,
isEuIterableService: false,
dangerouslyAllowJsPopups: false,
allowIframeScripts: false,
eventThresholdLimit: DEFAULT_EVENT_THRESHOLD_LIMIT,
identityResolution: {
replayOnVisitorToKnown: true,
Expand Down
Loading