diff --git a/frontend/src/metabase-types/store/embed.ts b/frontend/src/metabase-types/store/embed.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1e5bb3414f82a05fc61dcd8903d054bb7fd0324f
--- /dev/null
+++ b/frontend/src/metabase-types/store/embed.ts
@@ -0,0 +1,10 @@
+export interface EmbedOptions {
+  top_nav?: boolean;
+  search?: boolean;
+  new_button?: boolean;
+  side_nav?: boolean | "default";
+}
+
+export interface EmbedState {
+  options: EmbedOptions;
+}
diff --git a/frontend/src/metabase-types/store/index.ts b/frontend/src/metabase-types/store/index.ts
index 9a4bd5500d0cde49c26b971dd497a45f18de2b7c..fe6a10c8255910499d431c456cd6a98080ee1246 100644
--- a/frontend/src/metabase-types/store/index.ts
+++ b/frontend/src/metabase-types/store/index.ts
@@ -1,5 +1,6 @@
 export * from "./admin";
 export * from "./app";
+export * from "./embed";
 export * from "./entities";
 export * from "./forms";
 export * from "./settings";
diff --git a/frontend/src/metabase-types/store/mocks/embed.ts b/frontend/src/metabase-types/store/mocks/embed.ts
new file mode 100644
index 0000000000000000000000000000000000000000..08b4d0b451694c318919e2a67e25678ee7ab5848
--- /dev/null
+++ b/frontend/src/metabase-types/store/mocks/embed.ts
@@ -0,0 +1,12 @@
+import { EmbedOptions, EmbedState } from "metabase-types/store";
+
+export const createMockEmbedOptions = (opts?: Partial<EmbedOptions>) => ({
+  ...opts,
+});
+
+export const createMockEmbedState = (
+  opts?: Partial<EmbedState>,
+): EmbedState => ({
+  options: createMockEmbedOptions(),
+  ...opts,
+});
diff --git a/frontend/src/metabase-types/store/mocks/index.ts b/frontend/src/metabase-types/store/mocks/index.ts
index 01343301932b7d843cfb485b29abf48a74c3de80..b3215315b9a0c01bea49f5e98b28a9dd90f1393d 100644
--- a/frontend/src/metabase-types/store/mocks/index.ts
+++ b/frontend/src/metabase-types/store/mocks/index.ts
@@ -1,5 +1,6 @@
 export * from "./admin";
 export * from "./app";
+export * from "./embed";
 export * from "./entities";
 export * from "./forms";
 export * from "./qb";
diff --git a/frontend/src/metabase-types/store/mocks/state.ts b/frontend/src/metabase-types/store/mocks/state.ts
index 5b80c6d644c2c6d826beda278fc5004c52262d59..e7a05e80c7c8bac11d4b4c2de7614e2d23702e22 100644
--- a/frontend/src/metabase-types/store/mocks/state.ts
+++ b/frontend/src/metabase-types/store/mocks/state.ts
@@ -3,17 +3,19 @@ import { createMockUser } from "metabase-types/api/mocks";
 import {
   createMockAdminState,
   createMockAppState,
-  createMockSettingsState,
+  createMockEmbedState,
   createMockEntitiesState,
+  createMockFormState,
   createMockQueryBuilderState,
+  createMockSettingsState,
   createMockSetupState,
-  createMockFormState,
 } from "metabase-types/store/mocks";
 
 export const createMockState = (opts?: Partial<State>): State => ({
   admin: createMockAdminState(),
   app: createMockAppState(),
   currentUser: createMockUser(),
+  embed: createMockEmbedState(),
   entities: createMockEntitiesState(),
   form: createMockFormState(),
   qb: createMockQueryBuilderState(),
diff --git a/frontend/src/metabase-types/store/state.ts b/frontend/src/metabase-types/store/state.ts
index dc079ead7c0b50595450a022b763c66b1b1dd9b7..9a7613ef12d7852e61a2da2c7148721bd1d980c8 100644
--- a/frontend/src/metabase-types/store/state.ts
+++ b/frontend/src/metabase-types/store/state.ts
@@ -1,6 +1,7 @@
 import { User } from "metabase-types/api";
 import { AdminState } from "./admin";
 import { AppState } from "./app";
+import { EmbedState } from "./embed";
 import { EntitiesState } from "./entities";
 import { FormState } from "./forms";
 import { QueryBuilderState } from "./qb";
@@ -11,6 +12,7 @@ export interface State {
   admin: AdminState;
   app: AppState;
   currentUser: User;
+  embed: EmbedState;
   entities: EntitiesState;
   form: FormState;
   qb: QueryBuilderState;
diff --git a/frontend/src/metabase/App.tsx b/frontend/src/metabase/App.tsx
index 34fe4103e5c8e753e7524269cd9d92c992789667..98e2c390440c1fb40a6126531861421d14ee278c 100644
--- a/frontend/src/metabase/App.tsx
+++ b/frontend/src/metabase/App.tsx
@@ -1,6 +1,5 @@
 import React, { ErrorInfo, ReactNode, useMemo, useState } from "react";
 import { connect } from "react-redux";
-import _ from "underscore";
 import { Location } from "history";
 
 import AppErrorCard from "metabase/components/AppErrorCard/AppErrorCard";
@@ -15,6 +14,7 @@ import {
 import UndoListing from "metabase/containers/UndoListing";
 
 import { getErrorPage } from "metabase/selectors/app";
+import { getEmbedOptions } from "metabase/selectors/embed";
 import { getUser } from "metabase/selectors/user";
 import { getIsEditing as getIsEditingDashboard } from "metabase/dashboard/selectors";
 import { useOnMount } from "metabase/hooks/use-on-mount";
@@ -25,7 +25,7 @@ import Navbar from "metabase/nav/containers/Navbar";
 import StatusListing from "metabase/status/containers/StatusListing";
 
 import { User } from "metabase-types/api";
-import { AppErrorDescriptor, State } from "metabase-types/store";
+import { AppErrorDescriptor, EmbedOptions, State } from "metabase-types/store";
 
 import { AppContentContainer, AppContent } from "./App.styled";
 
@@ -58,6 +58,8 @@ interface AppStateProps {
   currentUser?: User;
   errorPage: AppErrorDescriptor | null;
   isEditingDashboard: boolean;
+  isEmbedded: boolean;
+  embedOptions: EmbedOptions;
 }
 
 interface AppRouterOwnProps {
@@ -72,6 +74,8 @@ function mapStateToProps(state: State): AppStateProps {
     currentUser: getUser(state),
     errorPage: getErrorPage(state),
     isEditingDashboard: getIsEditingDashboard(state),
+    isEmbedded: IFRAMED,
+    embedOptions: getEmbedOptions(state),
   };
 }
 
@@ -92,6 +96,8 @@ function App({
   errorPage,
   location: { pathname, hash },
   isEditingDashboard,
+  isEmbedded,
+  embedOptions,
   children,
 }: AppProps) {
   const [errorInfo, setErrorInfo] = useState<ErrorInfo | null>(null);
@@ -106,19 +112,22 @@ function App({
     if (!currentUser || isEditingDashboard) {
       return false;
     }
-    if (IFRAMED) {
+    if (isEmbedded && !embedOptions.side_nav) {
+      return false;
+    }
+    if (isEmbedded && embedOptions.side_nav === "default") {
       return EMBEDDED_ROUTES_WITH_NAVBAR.some(pattern =>
         pattern.test(pathname),
       );
     }
     return !PATHS_WITHOUT_NAVBAR.some(pattern => pattern.test(pathname));
-  }, [currentUser, pathname, isEditingDashboard]);
+  }, [currentUser, pathname, isEditingDashboard, isEmbedded, embedOptions]);
 
   const hasAppBar = useMemo(() => {
     const isFullscreen = hash.includes("fullscreen");
     if (
       !currentUser ||
-      IFRAMED ||
+      (isEmbedded && !embedOptions.top_nav) ||
       isAdminApp ||
       isEditingDashboard ||
       isFullscreen
@@ -126,7 +135,15 @@ function App({
       return false;
     }
     return !PATHS_WITHOUT_NAVBAR.some(pattern => pattern.test(pathname));
-  }, [currentUser, pathname, isEditingDashboard, isAdminApp, hash]);
+  }, [
+    currentUser,
+    pathname,
+    isEditingDashboard,
+    isEmbedded,
+    embedOptions,
+    isAdminApp,
+    hash,
+  ]);
 
   return (
     <ErrorBoundary onError={setErrorInfo}>
diff --git a/frontend/src/metabase/lib/browser.js b/frontend/src/metabase/lib/browser.js
index 11b5e5a149677029f93c558c84b0bcac7855ef26..094afc17a4ef2cd514743a286ec4cb84f5b87dfc 100644
--- a/frontend/src/metabase/lib/browser.js
+++ b/frontend/src/metabase/lib/browser.js
@@ -1,7 +1,8 @@
 import querystring from "querystring";
 
-export function parseHashOptions(hash) {
-  const options = querystring.parse(hash.replace(/^#/, ""));
+function parseQueryStringOptions(s) {
+  const options = querystring.parse(s);
+
   for (const name in options) {
     if (options[name] === "") {
       options[name] = true;
@@ -9,9 +10,18 @@ export function parseHashOptions(hash) {
       options[name] = JSON.parse(options[name]);
     }
   }
+
   return options;
 }
 
+export function parseHashOptions(hash) {
+  return parseQueryStringOptions(hash.replace(/^#/, ""));
+}
+
+export function parseSearchOptions(search) {
+  return parseQueryStringOptions(search.replace(/^\?/, ""));
+}
+
 export function stringifyHashOptions(options) {
   return querystring.stringify(options).replace(/=true\b/g, "");
 }
diff --git a/frontend/src/metabase/lib/embed.js b/frontend/src/metabase/lib/embed.js
index 5a22ca670d9af169e1007041c79cba1db998b037..dc3aec422569ff2f48fbadb196dd9832c312db2a 100644
--- a/frontend/src/metabase/lib/embed.js
+++ b/frontend/src/metabase/lib/embed.js
@@ -1,9 +1,8 @@
 import { push } from "react-router-redux";
-
 import _ from "underscore";
-
+import { parseSearchOptions } from "metabase/lib/browser";
 import { IFRAMED, IFRAMED_IN_SELF } from "metabase/lib/dom";
-
+import { setOptions } from "metabase/redux/embed";
 import { isFitViewportMode } from "metabase/hoc/FitViewPort";
 
 // detect if this page is embedded in itself, i.e. it's a embed preview
@@ -42,6 +41,7 @@ export function initializeEmbedding(store) {
         }
       }
     });
+    store.dispatch(setOptions(parseSearchOptions(window.location.search)));
   }
 }
 
diff --git a/frontend/src/metabase/nav/containers/AppBar.styled.tsx b/frontend/src/metabase/nav/containers/AppBar.styled.tsx
index 661fcfdccdbe145ef102a3a82aad0b2a381c34a2..89f51d5743117394b2bbd52417f3d54a6764cb66 100644
--- a/frontend/src/metabase/nav/containers/AppBar.styled.tsx
+++ b/frontend/src/metabase/nav/containers/AppBar.styled.tsx
@@ -30,8 +30,7 @@ export const LogoLink = styled(Link)`
   justify-content: center;
   border-radius: 6px;
   left: 0;
-  padding: ${space(1)};
-  padding-left: ${space(2)};
+  padding: ${space(1)} ${space(2)};
   margin-left: ${space(2)};
   position: absolute;
   transition: opacity 0.3s;
@@ -58,6 +57,7 @@ export const SidebarButtonContainer = styled.div`
 `;
 
 export interface LeftContainerProps {
+  isLogoActive: boolean;
   isSearchActive: boolean;
 }
 
@@ -70,12 +70,12 @@ export const LeftContainer = styled.div<LeftContainerProps>`
 
   &:hover {
     ${LogoLink} {
-      opacity: 0;
-      pointer-events: none;
+      opacity: ${props => (props.isLogoActive ? 1 : 0)};
+      pointer-events: ${props => (props.isLogoActive ? "" : "none")};
     }
 
     ${SidebarButtonContainer} {
-      opacity: 1;
+      opacity: ${props => (props.isLogoActive ? 0 : 1)};
     }
   }
 
diff --git a/frontend/src/metabase/nav/containers/AppBar.tsx b/frontend/src/metabase/nav/containers/AppBar.tsx
index e562ad78a062cef542ff58e138f74e0d559f8ea6..a1ba149bf7e79e4309d03dcdec8eadb201aa7907 100644
--- a/frontend/src/metabase/nav/containers/AppBar.tsx
+++ b/frontend/src/metabase/nav/containers/AppBar.tsx
@@ -11,11 +11,12 @@ import SearchBar from "metabase/nav/components/SearchBar";
 import SidebarButton from "metabase/nav/components/SidebarButton";
 import NewButton from "metabase/nav/containers/NewButton";
 
-import { State } from "metabase-types/store";
+import { EmbedOptions, State } from "metabase-types/store";
 
 import { getIsNavbarOpen, closeNavbar, toggleNavbar } from "metabase/redux/app";
 import { isMac } from "metabase/lib/browser";
-import { isSmallScreen } from "metabase/lib/dom";
+import { IFRAMED, isSmallScreen } from "metabase/lib/dom";
+import { getEmbedOptions } from "metabase/selectors/embed";
 
 import {
   AppBarRoot,
@@ -30,6 +31,8 @@ import {
 
 type Props = {
   isNavbarOpen: boolean;
+  isEmbedded: boolean;
+  embedOptions: EmbedOptions;
   toggleNavbar: () => void;
   closeNavbar: () => void;
 };
@@ -37,6 +40,8 @@ type Props = {
 function mapStateToProps(state: State) {
   return {
     isNavbarOpen: getIsNavbarOpen(state),
+    isEmbedded: IFRAMED,
+    embedOptions: getEmbedOptions(state),
   };
 }
 
@@ -53,8 +58,17 @@ function HomepageLink({ handleClick }: { handleClick: () => void }) {
   );
 }
 
-function AppBar({ isNavbarOpen, toggleNavbar, closeNavbar }: Props) {
+function AppBar({
+  isNavbarOpen,
+  isEmbedded,
+  embedOptions,
+  toggleNavbar,
+  closeNavbar,
+}: Props) {
   const [isSearchActive, setSearchActive] = useState(false);
+  const hasSearch = !isEmbedded || embedOptions.search;
+  const hasNewButton = !isEmbedded || embedOptions.new_button;
+  const hasSidebar = !isEmbedded || embedOptions.side_nav;
 
   const onLogoClick = useCallback(() => {
     if (isSmallScreen()) {
@@ -83,33 +97,42 @@ function AppBar({ isNavbarOpen, toggleNavbar, closeNavbar }: Props) {
 
   return (
     <AppBarRoot>
-      <LeftContainer isSearchActive={isSearchActive}>
+      <LeftContainer isLogoActive={!hasSidebar} isSearchActive={isSearchActive}>
         <HomepageLink handleClick={onLogoClick} />
-        <SidebarButtonContainer>
-          <Tooltip tooltip={sidebarButtonTooltip} isEnabled={!isSmallScreen()}>
-            <SidebarButton
-              isSidebarOpen={isNavbarOpen}
-              onClick={toggleNavbar}
-            />
-          </Tooltip>
-        </SidebarButtonContainer>
+        {hasSidebar && (
+          <SidebarButtonContainer>
+            <Tooltip
+              tooltip={sidebarButtonTooltip}
+              isEnabled={!isSmallScreen()}
+            >
+              <SidebarButton
+                isSidebarOpen={isNavbarOpen}
+                onClick={toggleNavbar}
+              />
+            </Tooltip>
+          </SidebarButtonContainer>
+        )}
       </LeftContainer>
       {!isSearchActive && (
         <MiddleContainer>
           <HomepageLink handleClick={onLogoClick} />
         </MiddleContainer>
       )}
-      <RightContainer>
-        <SearchBarContainer>
-          <SearchBarContent>
-            <SearchBar
-              onSearchActive={onSearchActive}
-              onSearchInactive={onSearchInactive}
-            />
-          </SearchBarContent>
-        </SearchBarContainer>
-        <NewButton />
-      </RightContainer>
+      {(hasSearch || hasNewButton) && (
+        <RightContainer>
+          {hasSearch && (
+            <SearchBarContainer>
+              <SearchBarContent>
+                <SearchBar
+                  onSearchActive={onSearchActive}
+                  onSearchInactive={onSearchInactive}
+                />
+              </SearchBarContent>
+            </SearchBarContainer>
+          )}
+          {hasNewButton && <NewButton />}
+        </RightContainer>
+      )}
     </AppBarRoot>
   );
 }
diff --git a/frontend/src/metabase/reducers-common.js b/frontend/src/metabase/reducers-common.js
index 1ac8a6d035194fcd96a3d7ecc88c0d30b5cafce7..621783dc9764be2925d228724bbd4914597c0476 100644
--- a/frontend/src/metabase/reducers-common.js
+++ b/frontend/src/metabase/reducers-common.js
@@ -2,6 +2,7 @@
 
 /* ducks */
 import app from "metabase/redux/app";
+import embed from "metabase/redux/embed";
 import requests from "metabase/redux/requests";
 import settings from "metabase/redux/settings";
 import undo from "metabase/redux/undo";
@@ -14,6 +15,7 @@ import { currentUser } from "metabase/redux/user";
 export default {
   // global reducers
   app,
+  embed,
   currentUser,
   // "entities" framework needs control over "requests" state
   requests: enhanceRequestsReducer(requests),
diff --git a/frontend/src/metabase/redux/embed.js b/frontend/src/metabase/redux/embed.js
new file mode 100644
index 0000000000000000000000000000000000000000..48cd5024d4b66f9cf7ea78016d4ac6e4c6a87be1
--- /dev/null
+++ b/frontend/src/metabase/redux/embed.js
@@ -0,0 +1,26 @@
+import {
+  combineReducers,
+  createAction,
+  handleActions,
+} from "metabase/lib/redux";
+
+const DEFAULT_OPTIONS = {
+  top_nav: false,
+  side_nav: "default",
+  search: false,
+  new_button: false,
+};
+
+export const SET_OPTIONS = "metabase/embed/SET_OPTIONS";
+export const setOptions = createAction(SET_OPTIONS);
+
+const options = handleActions(
+  {
+    [SET_OPTIONS]: (state, { payload }) => ({ ...DEFAULT_OPTIONS, ...payload }),
+  },
+  {},
+);
+
+export default combineReducers({
+  options,
+});
diff --git a/frontend/src/metabase/selectors/embed.ts b/frontend/src/metabase/selectors/embed.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a5e6ef8763eae5e95d6191a1965acc15dd0e0e48
--- /dev/null
+++ b/frontend/src/metabase/selectors/embed.ts
@@ -0,0 +1,5 @@
+import { State } from "metabase-types/store";
+
+export const getEmbedOptions = (state: State) => {
+  return state.embed.options;
+};