diff --git a/scripts/analytics/mongodb/queries/averageLevelPlaytimes.js b/scripts/analytics/mongodb/queries/averageLevelPlaytimes.js
index d3a889202..3119e2292 100644
--- a/scripts/analytics/mongodb/queries/averageLevelPlaytimes.js
+++ b/scripts/analytics/mongodb/queries/averageLevelPlaytimes.js
@@ -1,65 +1,41 @@
-// Average level playtimes by campaign
+// Average level playtimes in seconds by campaign, broken up by course and campaign levels
 
 // Usage:
 // mongo <address>:<port>/<database> <script file> -u <username> -p <password>
 
 // NOTE: faster to use find() instead of aggregate()
-// NOTE: faster to ask for one level at a time.  also keeps levels in campaign order
+// NOTE: faster to ask for one level at a time.
 
-// Excluded for one reason or another
-// Some relevant code:  https://github.com/codecombat/codecombat/blob/master/app/views/play/CampaignView.coffee#L281-L292
-var excludedLevels = ['deadly-dungeon-rescue', 'kithgard-brawl', 'cavern-survival', 'kithgard-mastery', 'destroying-angel', 'kithgard-apprentice', 'wild-horses', 'lost-viking', 'forest-flower-grove', 'boulder-woods', 'the-trials'];
+var courseCampaigns = ['intro', 'course-2', 'course-3', 'course-4'];
+var individualCampaigns = ['dungeon', 'forest', 'desert', 'mountain'];
 
 var scriptStartTime = new Date();
-var startDay = '2015-07-01';
-var endDay = '2015-08-06';
+var startDay = '2015-12-06';
+var endDay = '2015-12-13';
 
-log("Dates: " + startDay + " to " + endDay);
+print("Dates: " + startDay + " to " + endDay);
 
 // Print out playtimes for each campaign
-var campaigns = getCampaigns();
+var campaigns = getCampaigns(courseCampaigns);
+
 for (var i = 0; i < campaigns.length; i++) {
   var campaign = campaigns[i];
-  // if (campaign.slug !== 'dungeon') continue;
-  print(campaign.slug + " (free)");
-  var total = 0;
-
-  for (var j = 0; j < campaign.free.length; j++) {
-    var levelSlug = campaign.free[j];
-    if (excludedLevels.indexOf(levelSlug) >= 0) continue;
-    var data = getPlaytimes([levelSlug]);
-    print(data[levelSlug].average + "\t" + data[levelSlug].count + "\t" + levelSlug);
-    total += data[levelSlug];
-  }
-  // print(parseInt(total/60/60) + "\t\t total hours");
-  total = 0;
-
-  print(campaign.slug + " (paid)");
-  for (var j = 0; j < campaign.paid.length; j++) {
-    var levelSlug = campaign.paid[j];
-    if (excludedLevels.indexOf(levelSlug) >= 0) continue;
-    var data = getPlaytimes([levelSlug]);
-    if (data[levelSlug]) {
-      print(data[levelSlug].average + "\t" + data[levelSlug].count + "\t" + levelSlug);
-      total += data[levelSlug];
+  print(campaign.slug);
+  print("Sessions\tAverage\tSessions\tAverage\tLevel");
+  for (var j = 0; j < campaign.levelSlugs.length; j++) {
+    var levelSlug = campaign.levelSlugs[j];
+    var levelPlaytimes = getPlaytimes([levelSlug]);
+    if (levelPlaytimes[levelSlug]) {
+      print(levelPlaytimes[levelSlug].campaign.count,
+        '\t', levelPlaytimes[levelSlug].campaign.average,
+        '\t', levelPlaytimes[levelSlug].course.count,
+        '\t', levelPlaytimes[levelSlug].course.average,
+        '\t', levelSlug);
     }
     else {
-      print("0\t0\t" + levelSlug);
+      print(0, '\t', 0, '\t', 0, '\t', 0, '\t', levelSlug);
     }
   }
-  // print(parseInt(total/60/60) + "\t\t total hours");
-  total = 0;
-
-  print(campaign.slug + " (replayable)");
-  for (var j = 0; j < campaign.replayable.length; j++) {
-    var levelSlug = campaign.replayable[j];
-    if (excludedLevels.indexOf(levelSlug) >= 0) continue;
-    var data = getPlaytimes([levelSlug]);
-    print(data[levelSlug].average + "\t" + data[levelSlug].count + "\t" + levelSlug);
-    total += data[levelSlug];
-  }
-  // print(parseInt(total/60/60) + "\t\t total hours");
-
   // break;
 }
 
@@ -79,32 +55,32 @@ function objectIdWithTimestamp(timestamp) {
   return constructedObjectId
 }
 
-function getCampaigns() {
+function getCampaigns(campaignSlugs) {
   var campaigns = [];
-  var cursor = db.campaigns.find({}, {slug: 1, levels: 1});
+  var cursor = db.campaigns.find({slug: {$in: campaignSlugs}}, {slug: 1, levels: 1});
   var allFree = 0;
   var allpaid = 0;
   while (cursor.hasNext()) {
     var doc = cursor.next();
     if (doc.slug === 'auditions') continue;
-    var campaign = {slug: doc.slug, free: [], paid: [], replayable: []};
+    var campaign = {slug: doc.slug, levelSlugs: []};
     for (var levelID in doc.levels) {
-      if (doc.levels[levelID].replayable) {
-        campaign.replayable.push(doc.levels[levelID].slug);
-      }
-      else if (doc.levels[levelID].requiresSubscription) {
-        campaign.paid.push(doc.levels[levelID].slug);
-      }
-      else {
-        campaign.free.push(doc.levels[levelID].slug);
-      }
+      campaign.levelSlugs.push(doc.levels[levelID].slug);
     }
     campaigns.push(campaign);
   }
+
+  campaigns.sort(function (a, b) {
+    if (campaignSlugs.indexOf(a.slug) < campaignSlugs.indexOf(b.slug)){
+      return -1;
+    }
+    return 1;
+  });
   return campaigns;
 }
 
 function getPlaytimes(levelSlugs) {
+  // printjson(levelSlugs);
   var startObj = objectIdWithTimestamp(ISODate(startDay + "T00:00:00.000Z"));
   var endObj = objectIdWithTimestamp(ISODate(endDay + "T00:00:00.000Z"))
   var cursor = db['level.sessions'].find({
@@ -116,21 +92,49 @@ function getPlaytimes(levelSlugs) {
       {_id: {$gte: startObj}},
       {_id: {$lt: endObj}}
     ]
-  });
+  }, {heroConfig: 1, levelID: 1, playtime: 1});
 
   var playtimes = {};
   while (cursor.hasNext()) {
     var myDoc = cursor.next();
     var levelID = myDoc.levelID;
-    if (!playtimes[levelID]) playtimes[levelID] = [];
-    playtimes[levelID].push(myDoc.playtime);
+
+    if (!playtimes[levelID]) playtimes[levelID] = {campaign: [], course: []};
+    if (myDoc.heroConfig) {
+      playtimes[levelID].campaign.push(myDoc.playtime);
+    }
+    else {
+      playtimes[levelID].course.push(myDoc.playtime);
+    }
   }
+  // printjson(playtimes);
 
   var data = {};
   for (levelID in playtimes) {
-    var total = playtimes[levelID].reduce(function(a, b) {return a + b;});
-    data[levelID] = {count: playtimes[levelID].length, total: total};
-    data[levelID]['average'] = parseInt(total / playtimes[levelID].length);
+    var campaignTotal = 0;
+    var courseTotal = 0;
+    if (playtimes[levelID].campaign.length > 0) {
+      campaignTotal = playtimes[levelID].campaign.reduce(function(a, b) {return a + b;});
+    }
+    if (playtimes[levelID].course.length > 0) {
+      courseTotal = playtimes[levelID].course.reduce(function(a, b) {return a + b;});
+    }
+
+    var campaignAverage = parseInt(playtimes[levelID].campaign.length > 0 ? parseInt(campaignTotal / playtimes[levelID].campaign.length): 0);
+    var courseAverage = parseInt(playtimes[levelID].course.length > 0 ? parseInt(courseTotal / playtimes[levelID].course.length): 0);
+
+    data[levelID] = {
+      campaign: {
+        count: playtimes[levelID].campaign.length,
+        total: campaignTotal,
+        average: campaignAverage
+      },
+      course: {
+        count: playtimes[levelID].course.length,
+        total: courseTotal,
+        average: courseAverage
+      }
+    };
   }
   return data;
 }
diff --git a/scripts/analytics/mongodb/queries/campaignCompletionCounts.js b/scripts/analytics/mongodb/queries/campaignCompletionCounts.js
new file mode 100644
index 000000000..36ade5840
--- /dev/null
+++ b/scripts/analytics/mongodb/queries/campaignCompletionCounts.js
@@ -0,0 +1,106 @@
+// Campaign completion counts
+
+// Usage:
+// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
+
+var courseCampaigns = ['intro', 'course-2', 'course-3', 'course-4'];
+var individualCampaigns = ['dungeon', 'forest', 'desert', 'mountain'];
+
+var scriptStartTime = new Date();
+var startDay = '2015-11-08';
+var endDay = '2015-11-15';  // Not inclusive
+
+log("Dates: " + startDay + " to " + endDay);
+
+var campaigns = getCampaigns(courseCampaigns);
+// var campaigns = getCampaigns(individualCampaigns);
+// printjson(campaigns);
+
+for (var i = 0; i < campaigns.length; i++) {
+  var campaign = campaigns[i];
+  print(campaign.slug);
+  print("Total\tCampaign\tCourse\tLevel");
+  var completionCounts = getCompletionCounts(campaign.levelSlugs);
+  for (var j = 0; j < campaign.levelSlugs.length; j++) {
+    var levelSlug = campaign.levelSlugs[j];
+    if (completionCounts[levelSlug]) {
+      print(completionCounts[levelSlug].campaign + completionCounts[levelSlug].course,
+        '\t', completionCounts[levelSlug].campaign,
+        '\t', completionCounts[levelSlug].course,
+        '\t', levelSlug);
+    }
+    else {
+      print(0, '\t', 0, '\t', 0, '\t', levelSlug);
+    }
+  }
+}
+
+log("Script runtime: " + (new Date() - scriptStartTime));
+
+function log(str) {
+  print(new Date().toISOString() + " " + str);
+}
+
+function objectIdWithTimestamp(timestamp) {
+  // Convert string date to Date object (otherwise assume timestamp is a date)
+  if (typeof(timestamp) == 'string') timestamp = new Date(timestamp);
+  // Convert date object to hex seconds since Unix epoch
+  var hexSeconds = Math.floor(timestamp/1000).toString(16);
+  // Create an ObjectId with that hex timestamp
+  var constructedObjectId = ObjectId(hexSeconds + "0000000000000000");
+  return constructedObjectId
+}
+
+function getCampaigns(campaignSlugs) {
+  var campaigns = [];
+  var cursor = db.campaigns.find({slug: {$in: campaignSlugs}}, {slug: 1, levels: 1});
+  var allFree = 0;
+  var allpaid = 0;
+  while (cursor.hasNext()) {
+    var doc = cursor.next();
+    if (doc.slug === 'auditions') continue;
+    var campaign = {slug: doc.slug, levelSlugs: []};
+    for (var levelID in doc.levels) {
+      campaign.levelSlugs.push(doc.levels[levelID].slug);
+    }
+    campaigns.push(campaign);
+  }
+
+  campaigns.sort(function (a, b) {
+    if (campaignSlugs.indexOf(a.slug) < campaignSlugs.indexOf(b.slug)){
+      return -1;
+    }
+    return 1;
+  });
+  return campaigns;
+}
+
+function getCompletionCounts(levelSlugs) {
+  var startObj = objectIdWithTimestamp(ISODate(startDay + "T00:00:00.000Z"));
+  var endObj = objectIdWithTimestamp(ISODate(endDay + "T00:00:00.000Z"))
+  var cursor = db['level.sessions'].find({
+    $and:
+    [
+      {"state.complete": true},
+      {levelID: {$in: levelSlugs}},
+      {_id: {$gte: startObj}},
+      {_id: {$lt: endObj}}
+    ]
+  }, {heroConfig: 1, levelID: 1});
+
+  var completionCounts = {};
+  while (cursor.hasNext()) {
+    var myDoc = cursor.next();
+    var levelID = myDoc.levelID;
+
+    if (!completionCounts[levelID]) completionCounts[levelID] = {campaign: 0, course: 0};
+    if (myDoc.heroConfig) {
+      completionCounts[levelID].campaign++;
+    }
+    else {
+      completionCounts[levelID].course++;
+    }
+  }
+
+  return completionCounts;
+}