Push SDK Starter Kit
A effective guide to using the PUSH SDK and its features
This starter-kit is meant to showcase developers on how to use the PUSH SDK packages -
​
CRA-Typescript This particular kit is built out using CRA, Typescript. The SDK packages should also work out for React using plain JS.

git clone https://github.com/ethereum-push-notification-service/epns-sdk-starter-kit.git
cd epns-sdk-starter-kit
yarn install
yarn start

If you are trying to build out a separate dapp following this starter-kit example, some of the following dependencies might be required for the SDK and any dApp to work.
  1. 1.
    @epnsproject/sdk-uiweb has a peerDependency on styled-components
yarn add styled-components
2. Since its a dapp, the following are the web3 dependencies that you can install for wallet connection
yarn add ethers
3. The next package might only be needed if you are using web3-react. You are free to use any other React-based web3 solution.
yarn add @web3-react/core @web3-react/injected-connector
Note: No need to install these if you are using the starter-kit itself since we have already installed these for you so that you can focus on how to use the PUSH-SDK packages

The App has the following features-
Page
Features
SDK package used
Notifications
notifications, spams, subscribed modal
@epnsproject/sdk-uiweb, @epnsproject/sdk-restapi
Channels
get channel details for a specific channel, search for channel(s), get channel subscribers, is the logged-in user subscribed to the channel, opt in a channel, opt out a channel
@epnsproject/sdk-restapi
Payloads
send notification for different use cases
@epnsproject/sdk-restapi
Embed
sidebar notifications for the logged in user if subscribed on PUSH
@epnsproject/sdk-uiembed
We have extracted some snippets from the actual source code of the starter-kit files mentioned below to give you a snapshot view of what all SDK features are used in this dApp. But to make sure you are following along correctly please refer to the source code itself in the files mentioned.
Also the detailed SDK docs are hyperlinked in the feature's header itself
If you have got the wallet connection logic down, you can start referring from section 3 onwards.

Any dApp will require a wallet connection logic before it is usable. We have handled that for you in App.tsx. If you want to tinker around with that, check the below component.
import ConnectButton from './components/connect';

We basically derive the account, signer and some other wallet connection properties to use throughout the dApp with the SDK.
const { chainId, account, active, error, library } = useWeb3React();
We store this data in the web3Context and make it available across the dApp for later use.

import * as EpnsAPI from "@epnsproject/sdk-restapi";
import { NotificationItem, chainNameType, SubscribedModal } from '@epnsproject/sdk-uiweb';
const notifications = await EpnsAPI.user.getFeeds({
user: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // user address in CAIP
env: 'staging'
});
{notifications.map((oneNotification, i) => {
const {
cta,
title,
message,
app,
icon,
image,
url,
blockchain,
secret,
notification
} = oneNotification;
​
return (
<NotificationItem
key={`notif-${i}`}
notificationTitle={secret ? notification['title'] : title}
notificationBody={secret ? notification['body'] : message}
cta={cta}
app={app}
icon={icon}
image={image}
url={url}
theme={theme}
chainName={blockchain as chainNameType}
/>
);
})}

const spams = await EpnsAPI.user.getFeeds({
user: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // user address in CAIP
spam: true,
env: 'staging'
});
​Displaying Spams​
{spams ? (
<NotificationListContainer>
{spams.map((oneNotification, i) => {
const {
cta,
title,
message,
app,
icon,
image,
url,
blockchain,
secret,
notification
} = oneNotification;
​
return (
<NotificationItem
key={`spam-${i}`}
notificationTitle={secret ? notification['title'] : title}
notificationBody={secret ? notification['body'] : message}
cta={cta}
app={app}
icon={icon}
image={image}
url={url}
theme={theme}
chainName={blockchain as chainNameType}
// optional parameters for rendering spambox
isSpam
subscribeFn={subscribeFn} // see below
isSubscribedFn={isSubscribedFn} // see below
/>
);
})}
const subscribeFn = async () => {
// opt in to the spam notification item channel
}
we can use this @epnsproject/sdk-restapi method to do that - subscribe​
const isSubscribedFn = async () => {
// return boolean which says whether the channel for the
// spam notification item is subscribed or not by the user.
}
we can use this @epnsproject/sdk-restapi method to find out that - getSubscriptions​
Parsing raw Feeds API data using utils method parseApiResponse
Utils method to parse raw EPNS Feeds API response into a pre-defined shape as below.
// fetch some raw feeds data
const apiResponse = await EpnsAPI.user.getFeeds({
user: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // user address
raw: true,
env: 'staging'
});
// parse it to get a specific shape of object.
const parsedResults = EpnsAPI.utils.parseApiResponse(apiResponse);
​
const [oneNotification] = parsedResults;
​
// Now this object can be directly used by for e.g. "@epnsproject/sdk-uiweb" NotificationItem component as props.
​
const {
cta,
title,
message,
app,
icon,
image,
url,
blockchain,
secret,
notification
} = oneNotification;
We get the above keys after the parsing of the API repsonse.

const [showSubscribe, setShowSubscribe] = useState(false);
​
const toggleSubscribedModal = () => {
setShowSubscribe((lastVal) => !lastVal);
};
​
​
// JSX
{showSubscribe ? <SubscribedModal onClose={toggleSubscribedModal}/> : null}
CHANNELS PAGE (src/pages/channels/index.tsx)
import * as EpnsAPI from '@epnsproject/sdk-restapi';

const channelData = await EpnsAPI.channels.getChannel({
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // channel address in CAIP
env: 'staging'
});
const channelsData = await EpnsAPI.channels.search({
query: 'epns', // a search query
page: 1, // page index
limit: 20, // no of items per page
env: 'staging'
});
const subscribers = await EpnsAPI.channels._getSubscribers({
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // channel address in CAIP
env: 'staging'
});
const subscriptions = await EpnsAPI.user.getSubscriptions({
user: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // user address in CAIP
env: 'staging'
});
const _signer = library.getSigner(account); // from useWeb3()
//
//
//
await EpnsAPI.channels.subscribe({
signer: _signer,
channelAddress: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // channel address in CAIP
userAddress: 'eip155:42:0x52f856A160733A860ae7DC98DC71061bE33A28b3', // user address in CAIP
onSuccess: () => {
console.log('opt in success');
},
onError: () => {
console.error('opt in error');
},
env: 'staging'
})
const _signer = library.getSigner(account); // from useWeb3()
//
//
//
await EpnsAPI.channels.unsubscribe({
signer: _signer,
channelAddress: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // channel address in CAIP
userAddress: 'eip155:42:0x52f856A160733A860ae7DC98DC71061bE33A28b3', // user address in CAIP
onSuccess: () => {
console.log('opt out success');
},
onError: () => {
console.error('opt out error');
},
env: 'staging'
})
PAYLOADS PAGE (src/pages/payloads/index.tsx)

direct payload for single recipient(target)
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 3, // target
identityType: 2, // direct payload
notification: {
title: `[SDK-TEST] notification TITLE:`,
body: `[sdk-test] notification BODY`
},
payload: {
title: `[sdk-test] payload title`,
body: `sample msg body`,
cta: '',
img: ''
},
recipients: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // recipient address
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
direct payload for group of recipients(subset)
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 4, // subset
identityType: 2, // direct payload
notification: {
title: `[SDK-TEST] notification TITLE:`,
body: `[sdk-test] notification BODY`
},
payload: {
title: `[sdk-test] payload title`,
body: `sample msg body`,
cta: '',
img: ''
},
recipients: ['eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', 'eip155:42:0xCdBE6D076e05c5875D90fa35cc85694E1EAFBBd1'], // recipients addresses
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
direct payload for all recipients(broadcast)
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 1, // broadcast
identityType: 2, // direct payload
notification: {
title: `[SDK-TEST] notification TITLE:`,
body: `[sdk-test] notification BODY`
},
payload: {
title: `[sdk-test] payload title`,
body: `sample msg body`,
cta: '',
img: ''
},
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
IPFS payload for single recipient(target)
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 3, // target
identityType: 1, // ipfs payload
ipfsHash: 'bafkreicuttr5gpbyzyn6cyapxctlr7dk2g6fnydqxy6lps424mcjcn73we', // IPFS hash of the payload
recipients: 'eip155:42:0xCdBE6D076e05c5875D90fa35cc85694E1EAFBBd1', // recipient address
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
IPFS payload for group of recipients(subset)
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 4, // subset
identityType: 1, // ipfs payload
ipfsHash: 'bafkreicuttr5gpbyzyn6cyapxctlr7dk2g6fnydqxy6lps424mcjcn73we', // IPFS hash of the payload
recipients: ['eip155:42:0xCdBE6D076e05c5875D90fa35cc85694E1EAFBBd1', 'eip155:42:0x52f856A160733A860ae7DC98DC71061bE33A28b3'], // recipients addresses
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
IPFS payload for all recipients(broadcast)
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 1, // broadcast
identityType: 1, // direct payload
ipfsHash: 'bafkreicuttr5gpbyzyn6cyapxctlr7dk2g6fnydqxy6lps424mcjcn73we', // IPFS hash of the payload
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
minimal payload for single recipient(target)
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 3, // target
identityType: 0, // Minimal payload
notification: {
title: `[SDK-TEST] notification TITLE:`,
body: `[sdk-test] notification BODY`
},
payload: {
title: `[sdk-test] payload title`,
body: `sample msg body`,
cta: '',
img: ''
},
recipients: 'eip155:42:0xCdBE6D076e05c5875D90fa35cc85694E1EAFBBd1', // recipient address
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
minimal payload for a group of recipient(subset)
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 4, // subset
identityType: 0, // Minimal payload
notification: {
title: `[SDK-TEST] notification TITLE:`,
body: `[sdk-test] notification BODY`
},
payload: {
title: `[sdk-test] payload title`,
body: `sample msg body`,
cta: '',
img: ''
},
recipients: ['eip155:42:0xCdBE6D076e05c5875D90fa35cc85694E1EAFBBd1', 'eip155:42:0x52f856A160733A860ae7DC98DC71061bE33A28b3'], // recipients address
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
minimal payload for all recipients(broadcast)
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 1, // broadcast
identityType: 0, // Minimal payload
notification: {
title: `[SDK-TEST] notification TITLE:`,
body: `[sdk-test] notification BODY`
},
payload: {
title: `[sdk-test] payload title`,
body: `sample msg body`,
cta: '',
img: ''
},
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
graph payload for single recipient(target)
Make sure the channel has the graph id you are providing!!
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 3, // target
identityType: 3,
// Subgraph options
graph: {
id: '_your_graph_id',
counter: 3
},
recipients: 'eip155:42:0xCdBE6D076e05c5875D90fa35cc85694E1EAFBBd1', // recipient address
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
graph payload for group of recipients(subset)
Make sure the channel has the graph id you are providing!!
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 4, // subset
identityType: 3,
// Subgraph options
graph: {
id: '_your_graph_id',
counter: 3
},
recipients: ['eip155:42:0xCdBE6D076e05c5875D90fa35cc85694E1EAFBBd1', 'eip155:42:0x52f856A160733A860ae7DC98DC71061bE33A28b3'], // recipients addresses
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
graph payload for all recipients(broadcast)
Make sure the channel has the graph id you are providing!!
// apiResponse?.status === 204, if sent successfully!
const apiResponse = await EpnsAPI.payloads.sendNotification({
signer,
type: 1, // broadcast
identityType: 3,
// Subgraph options
graph: {
id: '_your_graph_id',
counter: 3
},
channel: 'eip155:42:0xD8634C39BBFd4033c0d3289C4515275102423681', // your channel address
env: 'staging'
});
EMBED PAGE (src/pages/embed/index.tsx)
import { useEffect, useContext } from 'react';
import { EmbedSDK } from "@epnsproject/sdk-uiembed";
import Web3Context from '../../context/web3Context';
​
const EmbedPage = () => {
const { account, chainId } = useContext<any>(Web3Context);
​
useEffect(() => {
if (account) { // 'your connected wallet address'
EmbedSDK.init({
chainId,
headerText: 'Hello Hacker Dashboard', // optional
targetID: 'sdk-trigger-id', // mandatory
appName: 'hackerApp', // mandatory
user: account, // mandatory
viewOptions: {
type: 'sidebar', // optional [default: 'sidebar', 'modal']
showUnreadIndicator: true, // optional
unreadIndicatorColor: '#cc1919',
unreadIndicatorPosition: 'top-right',
},
theme: 'light',
onOpen: () => {
console.log('-> client dApp onOpen callback');
},
onClose: () => {
console.log('-> client dApp onClose callback');
}
});
}
return () => {
EmbedSDK.cleanup();
};
}, [account, chainId]);
​
​
return (
<div>
<h2>Embed Test page</h2>
​
​
<button id="sdk-trigger-id">trigger button</button>
</div>
);
}
Copy link
On this page
Getting started
Dependencies
App walkthrough