Decorating sites with Browser Extensions
We're big fans of internet grocer FreshDirect in my household. When we lived in Brooklyn and now in North Jersey, we place a delivery order about once a week. While there is a lot I like about the service offering, there are a few features that could improve the user experience.
One of the big ones for me would be to associate WeightWatchers points values for each food on the site. It would save me a bunch of time and frustration if my wife and I would be able to see them while we were filling our cart.
I knew this was going to be a "fun" project since both FreshDirect and WeightWatchers do not offer public APIs. The two big challenges would be:
- How will I assign points values to foods?
- How can we effectively present the points information as part of the shopping experience without needing FreshDirect to make changes to their site?
Getting foods and their points values
The first requirement is that I need to associate the foods on their site with their respective points values. I wrote a process that spidered all of the category pages on FreshDirect.com and recorded Nutritional information for each product found. I then used that information to calculate the points values and saved it to a json file with the following format:
1
2
3
4
5
{ "items": [
{ "id":"gro_sprite_diet_le_02" ,"points": "0" },
{ "id":"cat_hldy_chsplatter" ,"points": "3" },
{ "id":"mea_pid_3335013" ,"points": "4" }
] }
Displaying values on FreshDirect.com
I needed a way to show the points values on FreshDirect.com without requiring them to make any changes. The only way I think of injecting content into a site was triggering some javascript during the user’s session. Lucky for me, that is exactly the purpose of browser extensions.
The first thing I did was open up a category page on FreshDirect.com in my Google Chrome browser. I opened Chrome’s javascript console (Ctrl+Shift+J) and wrote some code to parse the DOM looking for all the products on the page. I then inserted the points value under each product link. I took the code from the console and saved it to a file called contentscript.js.
I needed to get access to my json file with all the points values (for this exercise it is hosted locally at http://localhost/points-foods.txt). When I tried to access the json file, Chrome threw an error message that reminded me that most browsers will block calls to other sites to prevent malicious activities. While I could have gotten this to work with JSONP, extensions are designed to provide support for solving this problem.
To create a Chrome extension, you need a manifest.json file (a very basic example below). The “matches” attribute defines the domains you want the scripts in the extension to access. The “js” attribute defines the scripts that will execute when a user navigates to a page in one of those domains.
1
2
3
4
5
6
7
8
9
10
11
{
"name": "WeightWatchers Points Values",
"manifest_version": 2,
"version": "1.0.0.0",
"content_scripts": [{
"js": ["contentscript.js"],
"matches": ["https://www.freshdirect.com/*",
"http://www.freshdirect.com/*",
"http://localhost/*"]
}]
}
I opened chrome://extensions/ and checked the “Developer Mode” checkbox. I loaded the unpacked extension by navigating to the folder that contained contentscript.js and manifest.json files. On the screen below, you’ll see the WeightWatchers Points Values 1.0.0.0 available:
With the extension enabled, you’ll see the WeightWatchers points value injected below each product on the screen below (with the blue points icons):
Conclusions
- Seeing the points values changed our purchasing habits in some cases. We chose to buy a more expensive type of pork ribs because it was 5 points compared to the cheaper 9 point type we have ordered in the past. FreshDirect made more money and we were happy to make a healthier choice, that’s a win-win.
- I love loosely coupled design patterns (like decorators), where the systems can function completely independent of one another. This function works really well and it was built without any interaction of either FreshDirect or WeightWatchers.
- This was my first browser extension. There is amazing potential with this as a mechanism for delivering recommendations and personalized content. You just need to convince folks of the value to install/use your extension.
- My original project idea was to programmatically log into my Fresh Direct account and assign points values to all the food we had ordered (100+ orders). I spent about 3 hours to get to this work with Powershell code. Then I got more ambitious and decided to spider for all the products, which consumed another 2-3 hours.
- While I know I could have done this with far more elegant code using JQuery (since Chrome has the awesome Content Scripts support), I decided to use XMLHttpRequest and old school DOM parsing. This way the same code could be applied to other browsers that don't support content scripts.
I took about 4-5 hours to write all the javascript code and figure out how extensions work.
- Having the ability to see opinions of my specific social groups for products/content.
Maybe try some sentiment analysis with thumbs up/thumbs down indicators or ratings scores. I would love this for Netflix! - Enhancing shopping experiences and deal finders.
Would be awesome for something to tell me the popularity of an item and optimal bid amount while shopping on eBay. Then I could integrate the extension with my sniper with a single click. - Building productivity/administrative tools on top of my every day web applications (Gmail, banking, my sites, etc.)