diff --git a/web/components/profile/twitch-panel.tsx b/web/components/profile/twitch-panel.tsx
index b284b242..a37b21dc 100644
--- a/web/components/profile/twitch-panel.tsx
+++ b/web/components/profile/twitch-panel.tsx
@@ -6,38 +6,101 @@ import { LinkIcon } from '@heroicons/react/solid'
 import { usePrivateUser, useUser } from 'web/hooks/use-user'
 import { updatePrivateUser } from 'web/lib/firebase/users'
 import { track } from 'web/lib/service/analytics'
-import { linkTwitchAccountRedirect } from 'web/lib/twitch/link-twitch-account'
+import {
+  linkTwitchAccountRedirect,
+  updateBotEnabledForUser,
+} from 'web/lib/twitch/link-twitch-account'
 import { copyToClipboard } from 'web/lib/util/copy'
 import { Button, ColorType } from './../button'
 import { Row } from './../layout/row'
 import { LoadingIndicator } from './../loading-indicator'
+import { PrivateUser } from 'common/user'
 
 function BouncyButton(props: {
   children: ReactNode
   onClick?: MouseEventHandler<any>
   color?: ColorType
+  className?: string
 }) {
-  const { children, onClick, color } = props
+  const { children, onClick, color, className } = props
   return (
     <Button
       color={color}
       size="lg"
       onClick={onClick}
-      className="btn h-[inherit] flex-shrink-[inherit] border-none font-normal normal-case"
+      className={clsx(
+        'btn h-[inherit] flex-shrink-[inherit] border-none font-normal normal-case',
+        className
+      )}
     >
       {children}
     </Button>
   )
 }
 
+function BotConnectButton(props: {
+  privateUser: PrivateUser | null | undefined
+}) {
+  const { privateUser } = props
+  const [loading, setLoading] = useState(false)
+
+  const updateBotConnected = (connected: boolean) => async () => {
+    if (!privateUser) return
+    const twitchInfo = privateUser.twitchInfo
+    if (!twitchInfo) return
+
+    const error = connected
+      ? 'Failed to add bot to your channel'
+      : 'Failed to remove bot from your channel'
+    const success = connected
+      ? 'Added bot to your channel'
+      : 'Removed bot from your channel'
+
+    setLoading(true)
+    toast.promise(
+      updateBotEnabledForUser(privateUser, connected).then(() =>
+        updatePrivateUser(privateUser.id, {
+          twitchInfo: { ...twitchInfo, botEnabled: connected },
+        })
+      ),
+      { loading: 'Updating bot settings...', error, success }
+    )
+    try {
+    } finally {
+      setLoading(false)
+    }
+  }
+
+  return (
+    <>
+      {privateUser?.twitchInfo?.botEnabled ? (
+        <BouncyButton
+          color="red"
+          onClick={updateBotConnected(false)}
+          className={clsx(loading && 'btn-disabled')}
+        >
+          Remove bot from your channel
+        </BouncyButton>
+      ) : (
+        <BouncyButton
+          color="green"
+          onClick={updateBotConnected(true)}
+          className={clsx(loading && 'btn-disabled')}
+        >
+          Add bot to your channel
+        </BouncyButton>
+      )}
+    </>
+  )
+}
+
 export function TwitchPanel() {
   const user = useUser()
   const privateUser = usePrivateUser()
 
   const twitchInfo = privateUser?.twitchInfo
-  const twitchName = privateUser?.twitchInfo?.twitchName
-  const twitchToken = privateUser?.twitchInfo?.controlToken
-  const twitchBotConnected = privateUser?.twitchInfo?.botEnabled
+  const twitchName = twitchInfo?.twitchName
+  const twitchToken = twitchInfo?.controlToken
 
   const linkIcon = <LinkIcon className="mr-2 h-6 w-6" aria-hidden="true" />
 
@@ -55,13 +118,6 @@ export function TwitchPanel() {
     })
   }
 
-  const updateBotConnected = (connected: boolean) => async () => {
-    if (user && twitchInfo) {
-      twitchInfo.botEnabled = connected
-      await updatePrivateUser(user.id, { twitchInfo })
-    }
-  }
-
   const [twitchLoading, setTwitchLoading] = useState(false)
 
   const createLink = async () => {
@@ -115,17 +171,12 @@ export function TwitchPanel() {
               <BouncyButton color="indigo" onClick={copyDockLink}>
                 Copy dock link
               </BouncyButton>
-              {twitchBotConnected ? (
-                <BouncyButton color="red" onClick={updateBotConnected(false)}>
-                  Remove bot from your channel
-                </BouncyButton>
-              ) : (
-                <BouncyButton color="green" onClick={updateBotConnected(true)}>
-                  Add bot to your channel
-                </BouncyButton>
-              )}
             </div>
           </div>
+          <div className="mt-4" />
+          <div className="flex w-full">
+            <BotConnectButton privateUser={privateUser} />
+          </div>
         </div>
       )}
     </>
diff --git a/web/lib/twitch/link-twitch-account.ts b/web/lib/twitch/link-twitch-account.ts
index 36fb12b5..71bc847d 100644
--- a/web/lib/twitch/link-twitch-account.ts
+++ b/web/lib/twitch/link-twitch-account.ts
@@ -3,29 +3,33 @@ import { generateNewApiKey } from '../api/api-key'
 
 const TWITCH_BOT_PUBLIC_URL = 'https://king-prawn-app-5btyw.ondigitalocean.app' // TODO: Add this to env config appropriately
 
+async function postToBot(url: string, body: unknown) {
+  const result = await fetch(url, {
+    method: 'POST',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify(body),
+  })
+  const json = await result.json()
+  if (!result.ok) {
+    throw new Error(json.message)
+  } else {
+    return json
+  }
+}
+
 export async function initLinkTwitchAccount(
   manifoldUserID: string,
   manifoldUserAPIKey: string
 ): Promise<[string, Promise<{ twitchName: string; controlToken: string }>]> {
-  const response = await fetch(`${TWITCH_BOT_PUBLIC_URL}/api/linkInit`, {
-    method: 'POST',
-    headers: {
-      'Content-Type': 'application/json',
-    },
-    body: JSON.stringify({
-      manifoldID: manifoldUserID,
-      apiKey: manifoldUserAPIKey,
-      redirectURL: window.location.href,
-    }),
+  const response = await postToBot(`${TWITCH_BOT_PUBLIC_URL}/api/linkInit`, {
+    manifoldID: manifoldUserID,
+    apiKey: manifoldUserAPIKey,
+    redirectURL: window.location.href,
   })
-  const responseData = await response.json()
-  if (!response.ok) {
-    throw new Error(responseData.message)
-  }
   const responseFetch = fetch(
     `${TWITCH_BOT_PUBLIC_URL}/api/linkResult?userID=${manifoldUserID}`
   )
-  return [responseData.twitchAuthURL, responseFetch.then((r) => r.json())]
+  return [response.twitchAuthURL, responseFetch.then((r) => r.json())]
 }
 
 export async function linkTwitchAccountRedirect(
@@ -39,3 +43,22 @@ export async function linkTwitchAccountRedirect(
 
   window.location.href = twitchAuthURL
 }
+
+export async function updateBotEnabledForUser(
+  privateUser: PrivateUser,
+  botEnabled: boolean
+) {
+  if (botEnabled) {
+    return postToBot(`${TWITCH_BOT_PUBLIC_URL}/registerchanneltwitch`, {
+      apiKey: privateUser.apiKey,
+    }).then((r) => {
+      if (!r.success) throw new Error(r.message)
+    })
+  } else {
+    return postToBot(`${TWITCH_BOT_PUBLIC_URL}/unregisterchanneltwitch`, {
+      apiKey: privateUser.apiKey,
+    }).then((r) => {
+      if (!r.success) throw new Error(r.message)
+    })
+  }
+}
diff --git a/web/pages/profile.tsx b/web/pages/profile.tsx
index 6b70b5d2..44a63b2d 100644
--- a/web/pages/profile.tsx
+++ b/web/pages/profile.tsx
@@ -1,6 +1,6 @@
 import React, { useState } from 'react'
 import { RefreshIcon } from '@heroicons/react/outline'
-
+import { useRouter } from 'next/router'
 import { AddFundsButton } from 'web/components/add-funds-button'
 import { Page } from 'web/components/page'
 import { SEO } from 'web/components/SEO'
@@ -64,6 +64,7 @@ function EditUserField(props: {
 export default function ProfilePage(props: {
   auth: { user: User; privateUser: PrivateUser }
 }) {
+  const router = useRouter()
   const { user, privateUser } = props.auth
   const [avatarUrl, setAvatarUrl] = useState(user.avatarUrl || '')
   const [avatarLoading, setAvatarLoading] = useState(false)
@@ -237,8 +238,7 @@ export default function ProfilePage(props: {
               </button>
             </div>
           </div>
-
-          <TwitchPanel />
+          {router.query.twitch && <TwitchPanel />}
         </Col>
       </Col>
     </Page>
diff --git a/web/pages/twitch.tsx b/web/pages/twitch.tsx
index 7ca892e8..a21c1105 100644
--- a/web/pages/twitch.tsx
+++ b/web/pages/twitch.tsx
@@ -1,29 +1,34 @@
+import { PrivateUser, User } from 'common/user'
+import Link from 'next/link'
 import { useState } from 'react'
 
-import { Page } from 'web/components/page'
+import toast from 'react-hot-toast'
+import { Button } from 'web/components/button'
 import { Col } from 'web/components/layout/col'
-import { ManifoldLogo } from 'web/components/nav/manifold-logo'
-import { useSaveReferral } from 'web/hooks/use-save-referral'
-import { SEO } from 'web/components/SEO'
+import { Row } from 'web/components/layout/row'
 import { Spacer } from 'web/components/layout/spacer'
+import { LoadingIndicator } from 'web/components/loading-indicator'
+import { ManifoldLogo } from 'web/components/nav/manifold-logo'
+import { Page } from 'web/components/page'
+import { SEO } from 'web/components/SEO'
+import { Title } from 'web/components/title'
+import { useSaveReferral } from 'web/hooks/use-save-referral'
+import { useTracking } from 'web/hooks/use-tracking'
+import { usePrivateUser, useUser } from 'web/hooks/use-user'
 import { firebaseLogin, getUserAndPrivateUser } from 'web/lib/firebase/users'
 import { track } from 'web/lib/service/analytics'
-import { Row } from 'web/components/layout/row'
-import { Button } from 'web/components/button'
-import { useTracking } from 'web/hooks/use-tracking'
 import { linkTwitchAccountRedirect } from 'web/lib/twitch/link-twitch-account'
-import { usePrivateUser, useUser } from 'web/hooks/use-user'
-import { LoadingIndicator } from 'web/components/loading-indicator'
-import toast from 'react-hot-toast'
 
-export default function TwitchLandingPage() {
-  useSaveReferral()
-  useTracking('view twitch landing page')
+function TwitchPlaysManifoldMarkets(props: {
+  user?: User | null
+  privateUser?: PrivateUser | null
+}) {
+  const { user, privateUser } = props
 
-  const user = useUser()
-  const privateUser = usePrivateUser()
   const twitchUser = privateUser?.twitchInfo?.twitchName
 
+  const [isLoading, setLoading] = useState(false)
+
   const callback =
     user && privateUser
       ? () => linkTwitchAccountRedirect(user, privateUser)
@@ -37,8 +42,6 @@ export default function TwitchLandingPage() {
           await linkTwitchAccountRedirect(user, privateUser)
         }
 
-  const [isLoading, setLoading] = useState(false)
-
   const getStarted = async () => {
     try {
       setLoading(true)
@@ -53,6 +56,191 @@ export default function TwitchLandingPage() {
     }
   }
 
+  return (
+    <div>
+      <Row className="mb-4">
+        <img
+          src="/twitch-glitch.svg"
+          className="mb-[0.4rem] mr-4 inline h-10 w-10"
+        ></img>
+        <Title
+          text={'Twitch plays Manifold Markets'}
+          className={'!-my-0 md:block'}
+        />
+      </Row>
+      <Col className="gap-4">
+        <div>
+          Similar to Twitch channel point predictions, Manifold Markets allows
+          you to create and feature on stream any question you like with users
+          predicting to earn play money.
+        </div>
+        <div>
+          The key difference is that Manifold's questions function more like a
+          stock market and viewers can buy and sell shares over the course of
+          the event and not just at the start. The market will eventually
+          resolve to yes or no at which point the winning shareholders will
+          receive their profit.
+        </div>
+        Start playing now by logging in with Google and typing commands in chat!
+        {twitchUser ? (
+          <Button size="xl" color="green" className="btn-disabled self-center">
+            Account connected: {twitchUser}
+          </Button>
+        ) : isLoading ? (
+          <LoadingIndicator spinnerClassName="!w-11 !h-11" />
+        ) : (
+          <Button
+            size="xl"
+            color="gradient"
+            className="my-4 self-center !px-16"
+            onClick={getStarted}
+          >
+            Start playing
+          </Button>
+        )}
+        <div>
+          Instead of Twitch channel points we use our play money, mana (m$). All
+          viewers start with M$1000 and more can be earned for free and then{' '}
+          <Link href="/charity" className="underline">
+            donated to a charity
+          </Link>{' '}
+          of their choice at no cost!
+        </div>
+      </Col>
+    </div>
+  )
+}
+
+function Subtitle(props: { text: string }) {
+  const { text } = props
+  return <div className="text-2xl">{text}</div>
+}
+
+function Command(props: { command: string; desc: string }) {
+  const { command, desc } = props
+  return (
+    <div>
+      <p className="inline font-bold">{'!' + command}</p>
+      {' - '}
+      <p className="inline">{desc}</p>
+    </div>
+  )
+}
+
+function TwitchChatCommands() {
+  return (
+    <div>
+      <Title text="Twitch Chat Commands" className="md:block" />
+      <Col className="gap-4">
+        <Subtitle text="For Chat" />
+        <Command command="bet yes#" desc="Bets a # of Mana on yes." />
+        <Command command="bet no#" desc="Bets a # of Mana on no." />
+        <Command
+          command="sell"
+          desc="Sells all shares you own. Using this command causes you to
+          cash out early before the market resolves. This could be profitable
+          (if the probability has moved towards the direction you bet) or cause
+          a loss, although at least you keep some Mana. For maximum profit (but
+          also risk) it is better to not sell and wait for a favourable
+          resolution."
+        />
+        <Command command="balance" desc="Shows how much Mana you own." />
+        <Command command="allin yes" desc="Bets your entire balance on yes." />
+        <Command command="allin no" desc="Bets your entire balance on no." />
+
+        <Subtitle text="For Mods/Streamer" />
+        <Command
+          command="create <question>"
+          desc="Creates and features the question. Be careful... this will override any question that is currently featured."
+        />
+        <Command command="resolve yes" desc="Resolves the market as 'Yes'." />
+        <Command command="resolve no" desc="Resolves the market as 'No'." />
+        <Command
+          command="resolve n/a"
+          desc="Resolves the market as 'N/A' and refunds everyone their Mana."
+        />
+      </Col>
+    </div>
+  )
+}
+
+function BotSetupStep(props: {
+  stepNum: number
+  buttonName?: string
+  text: string
+}) {
+  const { stepNum, buttonName, text } = props
+  return (
+    <Col className="flex-1">
+      {buttonName && (
+        <>
+          <Button color="green">{buttonName}</Button>
+          <Spacer h={4} />
+        </>
+      )}
+      <div>
+        <p className="inline font-bold">Step {stepNum}. </p>
+        {text}
+      </div>
+    </Col>
+  )
+}
+
+function SetUpBot(props: { privateUser?: PrivateUser | null }) {
+  const { privateUser } = props
+  const twitchLinked = privateUser?.twitchInfo?.twitchName
+  return (
+    <>
+      <Title
+        text={'Set up the bot for your own stream'}
+        className={'!mb-4 md:block'}
+      />
+      <Col className="gap-4">
+        <img
+          src="https://raw.githubusercontent.com/PhilBladen/ManifoldTwitchIntegration/master/docs/OBS.png"
+          className="!-my-2"
+        ></img>
+        To add the bot to your stream make sure you have logged in then follow
+        the steps below.
+        {!twitchLinked && (
+          <Button
+            size="xl"
+            color="gradient"
+            className="my-4 self-center !px-16"
+            // onClick={getStarted}
+          >
+            Start playing
+          </Button>
+        )}
+        <div className="flex flex-col gap-6 sm:flex-row">
+          <BotSetupStep
+            stepNum={1}
+            buttonName={twitchLinked && 'Add bot to channel'}
+            text="Use the button above to add the bot to your channel. Then mod it by typing in your Twitch chat: /mod ManifoldBot (or whatever you named the bot) If the bot is modded it will not work properly on the backend."
+          />
+          <BotSetupStep
+            stepNum={2}
+            buttonName={twitchLinked && 'Overlay link'}
+            text="Create a new browser source in your streaming software such as OBS. Paste in the above link and resize it to your liking. We recommend setting the size to 400x400."
+          />
+          <BotSetupStep
+            stepNum={3}
+            buttonName={twitchLinked && 'Control dock link'}
+            text="The bot can be controlled entirely through chat. But we made an easy to use control panel. Share the link with your mods or embed it into your OBS as a custom dock."
+          />
+        </div>
+      </Col>
+    </>
+  )
+}
+
+export default function TwitchLandingPage() {
+  useSaveReferral()
+  useTracking('view twitch landing page')
+
+  const user = useUser()
+  const privateUser = usePrivateUser()
+
   return (
     <Page>
       <SEO
@@ -62,7 +250,7 @@ export default function TwitchLandingPage() {
       <div className="px-4 pt-2 md:mt-0 lg:hidden">
         <ManifoldLogo />
       </div>
-      <Col className="items-center">
+      {/* <Col className="items-center">
         <Col className="max-w-3xl">
           <Col className="mb-6 rounded-xl sm:m-12 sm:mt-0">
             <Row className="self-center">
@@ -114,6 +302,12 @@ export default function TwitchLandingPage() {
             )}
           </Col>
         </Col>
+      </Col> */}
+
+      <Col className="max-w-3xl gap-8 rounded bg-white p-10 text-gray-600 shadow-md sm:mx-auto">
+        <TwitchPlaysManifoldMarkets user={user} privateUser={privateUser} />
+        <TwitchChatCommands />
+        <SetUpBot privateUser={privateUser} />
       </Col>
     </Page>
   )
diff --git a/web/public/twitch-glitch.svg b/web/public/twitch-glitch.svg
new file mode 100644
index 00000000..3120fea7
--- /dev/null
+++ b/web/public/twitch-glitch.svg
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.6, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 2400 2800" style="enable-background:new 0 0 2400 2800;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#FFFFFF;}
+	.st1{fill:#9146FF;}
+</style>
+<title>Asset 2</title>
+<g>
+	<polygon class="st0" points="2200,1300 1800,1700 1400,1700 1050,2050 1050,1700 600,1700 600,200 2200,200 	"/>
+	<g>
+		<g id="Layer_1-2">
+			<path class="st1" d="M500,0L0,500v1800h600v500l500-500h400l900-900V0H500z M2200,1300l-400,400h-400l-350,350v-350H600V200h1600
+				V1300z"/>
+			<rect x="1700" y="550" class="st1" width="200" height="600"/>
+			<rect x="1150" y="550" class="st1" width="200" height="600"/>
+		</g>
+	</g>
+</g>
+</svg>