Jay Grossman

Decorating sites with Browser Extensions

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:

  1. How will I assign points values to foods?

  2. 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

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.
The follow on project:

Since I saw a lot of my friends were using seamless to order from local restaurants, so I wanted to put my extension concept to the test.
 
First there was some ground work to do:
- further built out my food catalog to over 500,000 foods + menu items at <span">restaurant chains</span> that published nutritional values.
- I cross referenced the menu items on the seamless ordering pages with my catalog (using the lucene search engine was a big help here).

User features:
- I displayed points values for food items on seamless menu pages (also on menupages.com and grubhub).
- I also displayed indicators when I had previously tracked a menu item that I had eaten (within my weight watchers food journal)
- If I clicked on the points icon, a modal appeared to track my food item in the food journal and/or share it on social media
 
Consistent with my activities on FreshDirect.com, I noticed that my lunch order choices changed because I had this new information. 
 
Future applications for browser extensions I hope to explore:

  1. 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!

  2. 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.

  3. Building productivity/administrative tools on top of my every day web applications (Gmail, banking, my sites, etc.)