diff --git a/app/lib/surface/Surface.coffee b/app/lib/surface/Surface.coffee
index 5f8ae5f49..fd278b8cc 100644
--- a/app/lib/surface/Surface.coffee
+++ b/app/lib/surface/Surface.coffee
@@ -515,7 +515,6 @@ module.exports = Surface = class Surface extends CocoClass
       break unless Dropper.drop()
     if frameAdvanced and not worldFrameAdvanced
       # We didn't end the above loop on an integer frame, so do the world state update.
-      console.log "Restore world state"
       @restoreWorldState()
 
     # these are skipped for dropped frames
diff --git a/app/locale/en.coffee b/app/locale/en.coffee
index e3c694f82..2766dda9c 100644
--- a/app/locale/en.coffee
+++ b/app/locale/en.coffee
@@ -179,6 +179,9 @@ module.exports = nativeDescription: "English", englishDescription: "English", tr
     victory_sign_up: "Sign Up to Save Progress"
     victory_sign_up_poke: "Want to save your code? Create a free account!"
     victory_rate_the_level: "Rate the level: "
+    victory_rank_my_game: "Rank My Game"
+    victory_ranking_game: "Submitting..."
+    victory_return_to_ladder: "Return to Ladder"
     victory_play_next_level: "Play Next Level"
     victory_go_home: "Go Home"
     victory_review: "Tell us more!"
diff --git a/app/templates/play/level/modal/victory.jade b/app/templates/play/level/modal/victory.jade
index 45c7f567f..6329f0bbe 100644
--- a/app/templates/play/level/modal/victory.jade
+++ b/app/templates/play/level/modal/victory.jade
@@ -14,8 +14,10 @@
     div!= body
   
   .modal-footer
-    if level.get('type') === 'ladder'
-      a.btn.btn-primary(href="/play/ladder/#{level.get('slug')}#my-matches", data-dismiss="modal", data-i18n="play_level.victory_go_home") Go Home
+    if readyToRank
+      button.btn.btn-success.rank-game-button(data-i18n="play_level.victory_rank_my_game") Rank My Game
+    else if level.get('type') === 'ladder'
+      a.btn.btn-primary(href="/play/ladder/#{level.get('slug')}#my-matches", data-dismiss="modal", data-i18n="play_level.victory_go_ladder") Return to Ladder
     else if hasNextLevel
       button.btn.btn-primary.next-level-button(data-dismiss="modal", data-i18n="play_level.victory_play_next_level") Play Next Level
     else
diff --git a/app/views/play/ladder/my_matches_tab.coffee b/app/views/play/ladder/my_matches_tab.coffee
index a5e679f1b..a094aef82 100644
--- a/app/views/play/ladder/my_matches_tab.coffee
+++ b/app/views/play/ladder/my_matches_tab.coffee
@@ -94,7 +94,6 @@ module.exports = class MyMatchesTabView extends CocoView
     c1 and not _.isEqual(c1, c2)
 
   rankSession: (e) ->
-    console.log "Clicked"
     button = $(e.target).closest('.rank-button')
     sessionID = button.data('session-id')
     session = _.find @sessions.models, { id: sessionID }
diff --git a/app/views/play/level/hud_view.coffee b/app/views/play/level/hud_view.coffee
index 9abd6d726..324c5e68b 100644
--- a/app/views/play/level/hud_view.coffee
+++ b/app/views/play/level/hud_view.coffee
@@ -316,7 +316,6 @@ module.exports = class HUDView extends View
     @timespans = {}
     dt = @thang.world.dt
     actionHistory = @thang.world.actionsForThang @thang.id, true
-    console.log "got actionHistory", actionHistory
     [lastFrame, lastAction] = [0, null]
     for hist in actionHistory.concat {frame: @thang.world.totalFrames, name: 'END'}
       [newFrame, newAction] = [hist.frame, hist.name]
diff --git a/app/views/play/level/modal/victory_modal.coffee b/app/views/play/level/modal/victory_modal.coffee
index 6773982ad..c71b2bcac 100644
--- a/app/views/play/level/modal/victory_modal.coffee
+++ b/app/views/play/level/modal/victory_modal.coffee
@@ -11,6 +11,7 @@ module.exports = class VictoryModal extends View
 
   events:
     'click .next-level-button': 'onPlayNextLevel'
+    'click .rank-game-button': 'onRankGame'
 
     # review events
     'mouseover .rating i': (e) -> @showStars(@starNum($(e.target)))
@@ -58,6 +59,21 @@ module.exports = class VictoryModal extends View
     @saveReview() if @$el.find('.review textarea').val()
     Backbone.Mediator.publish('play-next-level')
 
+  onRankGame: (e) ->
+    button = @$el.find('.rank-game-button')
+    button.text($.i18n.t('play_level.victory_ranking_game', defaultValue: 'Submitting...'))
+    button.prop 'disabled', true
+    ajaxData = session: @session.id, levelID: @level.id, originalLevelID: @level.get('original'), levelMajorVersion: @level.get('version').major
+    ladderURL = "/play/ladder/#{@level.get('slug')}#my-matches"
+    goToLadder = -> Backbone.Mediator.publish 'router:navigate', route: ladderURL
+    $.ajax '/queue/scoring',
+      type: 'POST'
+      data: ajaxData
+      success: goToLadder
+      failure: (response) ->
+        console.error "Couldn't submit game for ranking:", response
+        goToLadder()
+
   getRenderData: ->
     c = super()
     c.body = @body
@@ -65,6 +81,10 @@ module.exports = class VictoryModal extends View
     c.hasNextLevel = _.isObject(@level.get('nextLevel')) and (@level.get('name') isnt "Mobile Artillery")
     c.levelName = @level.get('i18n')?[me.lang()]?.name ? @level.get('name')
     c.level = @level
+    if c.level.get('type') is 'ladder'
+      c1 = @session?.get('code')
+      c2 = @session?.get('submittedCode')
+      c.readyToRank = @session.get('levelID') and c1 and not _.isEqual(c1, c2)
     if me.get 'hourOfCode'
       # Show the Hour of Code "I'm Done" tracking pixel after they played for 30 minutes
       elapsed = (new Date() - new Date(me.get('dateCreated')))