Desktop Solutions
Implementing Wildfire Coupons into an existing Chrome Extension
45min
the @wildlink/wildlink coupons module is a library designed to integrate your current existing extension with the ability to try and automatically apply coupons in real time the @wildlink/wildlink coupons module requires a few dependencies in order to work properly, and one of them being the wildlink js client you can view details about the wildlink js client package functionality here https //www npmjs com/package/wildlink js client https //www npmjs com/package/wildlink js client how it works the @wildlink/wildlink coupons module uses elements on the page to identify if the user is on a checkout page when the user is on the checkout page, we dispatch events to allow the application to show a ui to the user for when they want to apply the coupons once the start method in the foreground api is called, the coupons are applied one by one automatically the api will complete its process when one of the cases below are met there are no more coupons to apply the user has navigated away from the page we have reached the maxruntime once we have applied all of the coupons or if we have reached the runtime limit, the module will attempt to find the coupon that saves the most money, and apply it automatically requirements packages wildlink js client https //www npmjs com/package/wildlink js client permissions "storage" "unlimitedstorage" "tabs" "background" 💡 the unlimitedstorage permission is more of a recommendation than a requirement you will receive a warning in your background console when running without it, the lack of this permission may result in unexpected behavior content scripts must run at document start 💡 having your content scripts run at document start implies that the content script running the @wildlink/wildlink coupons library in the foreground will need to run at document start the reason for this is that you will need to initialize the @wildlink/wildlink coupons library in the foreground by calling its init method along with adding your own event listeners when doing the integration this process has a small start up time which will result in a race condition if done after the document has finished loading resulting in unexpected behavior when receiving the events from the background process manifest versions supported v2 v3 installation the @wildlink/wildlink coupons library is a private npm package please communicate with the wildfire team to get access and please avoid exposing the package on github or your source control management tool you will also need to install the wildlink js client package if you haven’t already terminal npm install @wildlink/wildlink coupons wildlink js client integration this section is split into two parts the background process is the javascript file that runs in the background process commonly referred to as background js, if you are using manifest version v3 you may refer to the background process as the service worker background import wildlinkcoupons from '@wildlink/wildlink coupons/background'; import { wildlinkclient } from 'wildlink js client'; const initializebackground = async () => { const client = new wildlinkclient('secret', 0); // < your application secret and application id from wildfire await client init(); const trackingcode = 'abc123'; // < the tracking code you use to identify your user to accredit cashback if you choose to do so, this is optional const wildlinkcoupons = new wildlinkcoupons({ client, trackingcode }); await wildlinkcoupons init(); wildlinkcoupons start(); }; constructor({client wildlinkclient, trackingcode? string, partnerapi? nspartnerapi ipartnerapi, debugmode? boolean}) client before passing in the wildlink client it must be initialized or this method will throw an error trackingcode the tracking code is used to track your user’s purchases this can be used to accredit your users with cash back if you choose to do so the tracking code is optional, and can be added later using the settrackingcode method the tracking code is commonly a user’s id partnerapi this is an optional api you may provide to inject your own coupons and targets into the module this will be explained further below debugmode this flag is false by default, but is used to display logs in the console when testing or debugging the application init() promise\<void> must be called when initializing the background process internally it initializes all of the necessary event listeners to communicate with the foreground library this step also validates your permissions set and will throw an error if the required permissions are missing start() void this method will be used when you want to explicitly start the library this will allow communication with the foreground process you can call this method later if you’d like for example only after the user has logged in, or accepted some terms and conditions by default, the library starts in a stopped state stop() void this method will be used when you want to explicitly stop the library this will stop all communication with the foreground process this method is useful for stopping the extension when the user has logged out, or ran out of some subscription foreground import wildlinkcoupons from '@wildlink/wildlink coupons/foreground'; const wildlinkcoupons = new wildlinkcoupons(); const initializeforeground = async () => { await wildlinkcoupons init(); injectreactcomponent(\<app wildlinkcoupons={wildlinkcoupons} />); }; 💡 this small code snippet uses react as an example but was designed to work in any framework you choose to use, including jquery or vanilla js foreground api explained constructor(debugmode? boolean) debugmode this flag is false by default, but is used to display logs in the console when testing or debugging the application init() promise\<void> must be called when initializing the foreground process internally it awakens the service worker if you are using manifest v3 this step also adds listeners to communicate with the background process cancel() promise\<void> must be called when the user dismisses your popup from your extension this frees up resources and prevents the foreground process from affecting your user’s experience maxruntime number this property gets and sets the maximum amount of time the module will apply coupons before completing the process by default this value is 60 once the coupons have been applying for more than 60 seconds, the module will automatically apply the code that saved the most money integrating your foreground process behavior with the library’s the wildlink coupons library in the foreground process extends from eventtarget supplied by the browser with some custom behavior we use custom events for your application to listen to, along with events to help update your ui and end the process as well foreground events name onready fires off when we are ready to apply coupons event interface { merchantname string; < the merchants name couponsfound number; < show the user how much coupons are ready to try onstart () => promise\<void>; < call when the user accepts the button to apply coupons } example wildlinkcoupons addeventlistener('onready', e => { const eventdata = e detail; console log(eventdata couponsfound); eventdata onstart(); }); name onnextcoupon fires off when we apply the next coupon, updates the progress in however your ui displays it event interface { progresspercentage number; < number from 0 100 to show the user progress } example wildlinkcoupons addeventlistener('onnextcoupon', e => { const eventdata = e detail; console log(eventdata progresspercentage); }); name oncomplete fires off when the coupons have finished applying event interface { wassuccessful boolean; < boolean that shows whether the user has saved money or not amountsaved number; < floating point number showing how much user has saved in usd workingcouponcode string; < the coupon code that worked and saved them money } example wildlinkcoupons addeventlistener('oncomplete', e => { const eventdata = e detail; console log(eventdata wassuccessful); console log(eventdata amountsaved); console log(eventdata workingcouponcode); }); name oncontinue fires off when the page has refreshed due to a coupon being applied, if we are still in a coupon session this will fire off and at this time you want to display your ui again event interface { merchantname string; < merchants name currentprogresspercentage number; < percentage of current progress } example wildlinkcoupons addeventlistener('oncontinue', e => { const eventdata = e detail; console log(eventdata wassuccessful); console log(eventdata amountsaved); console log(eventdata workingcouponcode); }); injecting your own coupons and targets into the module the module supports the ability for you to supply your own coupon codes and targets to merge with our own api's data providing a unified approach for you to extend the usability of the module how it works when instantiating the module you will provide your own api matching the following interface interface ipartnerapi { issupporteddomain(domains string\[]) promise\<boolean>; getsupporteddomain(domains string\[]) promise\<partnerdomain | null>; fetchcoupondata(domain string) promise\<coupons responsedata | null>; } here is an example implementation of what your api may look like // the implements keyword here is optional and only works in typescript // this just enforces the proper types in your class export class mypartnerapi implements nspartnerapi ipartnerapi { async issupporteddomain(domains string\[]) promise\<boolean> { // handle your logic to see if our list of domains are found in your data store // return true if any of the domains in the list are supported, or false if not return true; } async getsupporteddomain(domains string\[]) promise\<nspartnerapi partnerdomain | null> { // handle your logic to fetch a domain object containing information about the merchant return { activationurl '\<https //example activationurl com/123>', domain 'merchant com', merchant { name 'my merchant name', }, }; // or return null if you were unable to find a supported domain matching any domains in the list return null; } async fetchcoupondata(domain string) promise\<coupons responsedata | null> { // handle your api call for your coupon data return { codes \[ { id 0, code 'discount123', }, ], targets \[ { before '#before', error ' error div', id 0, input '#coupon code input', price '#total price', remove 'button remove', submit 'button submit', timeout 0, }, ], }; // or return null if not found return null; } } method implementation details the example calls are here to only show you examples of how we will be using your api internally you will not be calling these methods yourself issupporteddomain(domains string\[]) promise\<boolean> this method will be called on every web page the user visits in theory you would have a list of domains stored somewhere in the user's browser, and when this method is called, you will internally check that list to see if any of the domains in the argument exist in your data store example call if (await mypartnerapi issupporteddomain(\['shop macys com', 'macys com'])) { // internal logic } getsupporteddomain(domains string\[]) promise\<nspartnerapi partnerdomain | null> this method will not be called until issupporteddomain is called this gives you the freedom to make an api call without worrying about an api call being made on every single web page visit in theory this method will retrieve the domain information you will host on a server, or even on the user's device example call const hostnames = \['shop macys com', 'macys com']; if (await mypartnerapi issupporteddomain(hostnames)) { const domain = await mypartnerapi getsupporteddomain(hostnames); // we use your domain to fetch our internal data or your internal data } fetchcoupondata(domain string) promise\<coupons responsedata | null>; this method will be called to fetch the coupon and target data from your server we will not call this method until we have identified that your api will support this domain this keeps us from making an api call on every web page visit example call const hostnames = \['shop macys com', 'macys com']; if (await mypartnerapi issupporteddomain(hostnames)) { const domain = await mypartnerapi getsupporteddomain(hostnames); const coupondata = await mypartnerapi fetchcoupondata(domain domain); // use your coupon data along side ours in the coupon module } interface details nspartnerapi partnerdomain interface partnerdomain { domain string; activationurl string | null; merchant? { name string; }; } this interface is expected to be returned by getsupporteddomain this will be the data representing a domain you support with your own coupons and targets domain string this property in theory will be used to match the hostname example 'macys com' activationurl string | null this property will contain a url for you to affiliate yourself in the background if our own internal api does not support this merchant if you do not have a url to affiliate yourself for this merchant, you may leave this as null example '\<https //example activationurl com/123'> merchant? { name string; } this property is optional the merchant name will be used when dispatching the onready event if a merchant name is not provided, that event will dispatch a merchant name with an empty string example merchant { name 'my merchant name', }, coupons responsedata interface responsedata { targets target\[]; codes code\[]; } this interface is expected to be returned by fetchcoupondata it represents your coupon codes and targets and will be explained in further detail below targets target\[] interface target { readonly id number; readonly input string; readonly submit string | null; readonly remove string | null; readonly price string; readonly error string | null; readonly before string | null; readonly timeout number | null; } id number this property is used internally to identify targets by an id any targets your api will provide will be sanitized with ids set to 0 this prevents any confusion or errors when we store this information in our api for analytics purposes example 0 input string; this property is a string representing a css selector for the promo code field, where you type the coupon codes in example '#coupon code input' submit string | null; this property is a string representing a css selector for the element that you click to submit the coupon into the web page if your web page does not have a submit button, you may leave this as null if null is provided, the algorithm will attempt to either dispatch a submit event, or simulate and enter button press on the input field example 'button submit' remove string | null; this property is a string representing a css selector for the element that you click to remove the coupon code before applying another this property is required if you want the algorithm to apply the coupon that saves the most money if this is not provided, the algorithm will apply the first code that will work example 'button remove' price string; this property is a string representing a css selector for the element containing the total price, this is required for the algorithm to work properly example '#total price' error string | null; this property is a string representing a css selector for the element that displays an error when something has gone wrong this is completely optional and only set aside for future use example ' error div' before string | null; this property is a string representing a css selector for the element you click to show the input field when applying a coupon this is optional because not all web pages require you to click something to show the input field example '#before' timeout number this property is a number representing how many milliseconds to wait before we either submit the coupon or apply another, by default this is zero, if this value is zero we have our own default values we use in the extension example 1500 codes code\[] interface code { readonly id number; readonly code string; } id number this property is used internally to identify coupons by an id any coupons your api will provide will be sanitized with ids set to 0 this prevents any confusion or errors when we store this information in our api for analytics purposes code string this property is a string representing the coupon code the module will automatically exclude duplicates in your array, and will also remove any codes that are falsy (empty string, null, etc )