diff --git a/src/lib/app-state-hoc.jsx b/src/lib/app-state-hoc.jsx
index fe7ac023eab97c5df5aea8e5829a6769d28392b5..93d97180ef38526ac05feaf019338aa32ed4496b 100644
--- a/src/lib/app-state-hoc.jsx
+++ b/src/lib/app-state-hoc.jsx
@@ -10,6 +10,7 @@ import {setPlayer, setFullScreen} from '../reducers/mode.js';
 
 import locales from 'scratch-l10n';
 import {detectLocale} from './detect-locale';
+import {detectTutorialId} from './tutorial-from-url';
 
 const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
 
@@ -50,16 +51,27 @@ const AppStateHOC = function (WrappedComponent, localesOnly) {
                     guiInitialState,
                     guiMiddleware,
                     initFullScreen,
-                    initPlayer
+                    initPlayer,
+                    initTutorialCard
                 } = guiRedux;
                 const {ScratchPaintReducer} = require('scratch-paint');
 
                 let initializedGui = guiInitialState;
-                if (props.isFullScreen) {
-                    initializedGui = initFullScreen(initializedGui);
-                }
-                if (props.isPlayerOnly) {
-                    initializedGui = initPlayer(initializedGui);
+                if (props.isFullScreen || props.isPlayerOnly) {
+                    if (props.isFullScreen) {
+                        initializedGui = initFullScreen(initializedGui);
+                    }
+                    if (props.isPlayerOnly) {
+                        initializedGui = initPlayer(initializedGui);
+                    }
+                } else {
+                    const tutorialId = detectTutorialId();
+                    if (tutorialId !== null) {
+                        // When loading a tutorial from the URL,
+                        // load w/o preview modal
+                        // open requested tutorial card
+                        initializedGui = initTutorialCard(initializedGui, tutorialId);
+                    }
                 }
                 reducers = {
                     locales: localesReducer,
diff --git a/src/lib/libraries/decks/index.jsx b/src/lib/libraries/decks/index.jsx
index 096ca15224a7882aa7fe243efad76bf5b8a736cc..f8324f3ae73068221fe0b86bc68b5eb0757a9db5 100644
--- a/src/lib/libraries/decks/index.jsx
+++ b/src/lib/libraries/decks/index.jsx
@@ -99,7 +99,8 @@ export default {
                 'add-sprite'
             ]
         }
-        ]
+        ],
+        urlId: 1
     },
     'animate-a-name': {
         name: (
@@ -172,7 +173,8 @@ export default {
                 'glide-around'
             ]
         }
-        ]
+        ],
+        urlId: 2
     },
     'Make-Music': {
         name: (
@@ -239,7 +241,8 @@ export default {
                 'add-sprite'
             ]
         }
-        ]
+        ],
+        urlId: 3
     },
     'Make-A-Game': {
         name: (
@@ -323,7 +326,8 @@ export default {
                 'move-around-with-arrow-keys'
             ]
         }
-        ]
+        ],
+        urlId: 4
     },
 
     'Chase-Game': {
@@ -425,7 +429,8 @@ export default {
                 'move-around-with-arrow-keys'
             ]
         }
-        ]
+        ],
+        urlId: 5
     },
     'add-sprite': {
         name: (
@@ -453,7 +458,8 @@ export default {
                     'switch-costume'
                 ]
             }
-        ]
+        ],
+        urlId: 6
     },
     'add-a-backdrop': {
         name: (
@@ -471,7 +477,8 @@ export default {
                 'change-size',
                 'switch-costume'
             ]
-        }]
+        }],
+        urlId: 7
     },
     'change-size': {
         name: (
@@ -489,7 +496,8 @@ export default {
                 'glide-around',
                 'spin-video'
             ]
-        }]
+        }],
+        urlId: 8
     },
     'glide-around': {
         name: (
@@ -507,7 +515,8 @@ export default {
                 'add-a-backdrop',
                 'switch-costume'
             ]
-        }]
+        }],
+        urlId: 9
     },
 
     'record-a-sound': {
@@ -526,8 +535,8 @@ export default {
                 'Make-Music',
                 'switch-costume'
             ]
-        }]
-
+        }],
+        urlId: 10
     },
     'spin-video': {
         name: (
@@ -545,7 +554,8 @@ export default {
                 'add-a-backdrop',
                 'switch-costume'
             ]
-        }]
+        }],
+        urlId: 11
     },
     'hide-and-show': {
         name: (
@@ -563,7 +573,8 @@ export default {
                 'add-a-backdrop',
                 'switch-costume'
             ]
-        }]
+        }],
+        urlId: 12
     },
 
     'switch-costume': {
@@ -582,7 +593,8 @@ export default {
                 'add-a-backdrop',
                 'add-effects'
             ]
-        }]
+        }],
+        urlId: 13
     },
 
     'move-around-with-arrow-keys': {
@@ -601,7 +613,8 @@ export default {
                 'add-a-backdrop',
                 'switch-costume'
             ]
-        }]
+        }],
+        urlId: 14
     },
     'add-effects': {
         name: (
@@ -619,6 +632,7 @@ export default {
                 'add-a-backdrop',
                 'switch-costume'
             ]
-        }]
+        }],
+        urlId: 15
     }
 };
diff --git a/src/lib/tutorial-from-url.js b/src/lib/tutorial-from-url.js
new file mode 100644
index 0000000000000000000000000000000000000000..c627b8db7abf1a709719c12add3b6eec64f13257
--- /dev/null
+++ b/src/lib/tutorial-from-url.js
@@ -0,0 +1,48 @@
+/**
+ * @fileoverview
+ * Utility function to detect tutorial id from query paramenter on the URL.
+ */
+
+import tutorials from './libraries/decks/index.jsx';
+import analytics from './analytics';
+
+/**
+ * Get the tutorial id from the given numerical id (representing the
+ * url id of the tutorial).
+ * @param {number} urlId The URL Id for the tutorial
+ * @returns {string} The string id for the tutorial, or null if the URL ID
+ * was not found.
+ */
+const getDeckIdFromUrlId = urlId => {
+    for (const deckId in tutorials) {
+        if (tutorials[deckId].urlId === urlId) {
+            analytics.event({
+                category: 'how-to',
+                action: 'load from url',
+                label: `${deckId}`
+            });
+            return deckId;
+        }
+    }
+    return null;
+};
+
+/**
+ * Check if there's a tutorial id provided as a query parameter in the URL.
+ * Return the corresponding tutorial id or null if not found.
+ * @return {string} The ID of the requested tutorial or null if no tutorial was
+ * requested or found.
+ */
+const detectTutorialId = () => {
+    if (window.location.search.indexOf('tutorial=') !== -1) {
+        const urlTutorialId = window.location.search.match(/(?:tutorial)=(\d+)/)[1];
+        if (urlTutorialId) {
+            return getDeckIdFromUrlId(Number(urlTutorialId));
+        }
+    }
+    return null;
+};
+
+export {
+    detectTutorialId
+};
diff --git a/src/reducers/gui.js b/src/reducers/gui.js
index cfad8f6825ddad3a07a56b4c62757ffbc3a97909..8869c1a35031e1d46b8dd28f4f408d2500946840 100644
--- a/src/reducers/gui.js
+++ b/src/reducers/gui.js
@@ -21,6 +21,8 @@ import vmReducer, {vmInitialState} from './vm';
 import vmStatusReducer, {vmStatusInitialState} from './vm-status';
 import throttle from 'redux-throttle';
 
+import decks from '../lib/libraries/decks/index.jsx';
+
 const guiMiddleware = compose(applyMiddleware(throttle(300, {leading: true, trailing: true})));
 
 const guiInitialState = {
@@ -67,6 +69,27 @@ const initFullScreen = function (currentState) {
     );
 };
 
+const initTutorialCard = function (currentState, deckId) {
+    return Object.assign(
+        {},
+        currentState,
+        {
+            modals: {
+                previewInfo: false
+            },
+            cards: {
+                visible: true,
+                content: decks,
+                activeDeckId: deckId,
+                step: 0,
+                x: 0,
+                y: 0,
+                dragging: false
+            }
+        }
+    );
+};
+
 const guiReducer = combineReducers({
     assetDrag: assetDragReducer,
     blockDrag: blockDragReducer,
@@ -95,5 +118,6 @@ export {
     guiInitialState,
     guiMiddleware,
     initFullScreen,
-    initPlayer
+    initPlayer,
+    initTutorialCard
 };