Distribution & Monetization


+Peng Ying
+Mihai Ionescu

November 1st-15th 2011 GDD
Hashtag: #gddmoney

Step 1. Build web app
Step 2. ???????
Step 3. Profit!

Distribution

Make it easy for users to discover great apps, extensions, and themes
Make it easy for developers and brands to reach the 200+ million Chrome users
  • One-time $5 developer registration fee
  • Multiple monetization models, including one-time, subscriptions and in-app payments
  • No review or approval process
  • No restrictions on advertising
  • No restrictions on the platform
Play 23% more and spend 147% more
100% more engagement

Let's do it - Build the manifest

{ "app": {
    "launch": {
      "urls": ["https://chrome.google.com/webstore"],
      "web_url": "https://chrome.google.com/webstore",
      "container": "tab"
    }
  },
  "permissions": [],
  "icons": {
    "16": "16.png",
    "128": "128.png"
  },
  "name": "Chrome Web Store - Apps, Extensions and Themes",
  "description": "Discover great apps, games, extensions and...
     themes for Google Chrome.",
  "version": "1.0."
}

Let's do it - Create the images

Required

  • Icons - a 16x16 and a 128x128 application icon
  • Screen Shots - at least 1 screen shot (400x275)

Optional*

  • YouTube Video - promote your application with a short video
  • Promotional Images - banners used if your app is featured
  • Customized Header Background - increase the professional look of your app

* but highly recommended!

Let's do it - Upload to the Chrome Web Store

  1. Zip the manifest and two icon files together
  2. Upload the zip file to the Chrome Web Store via the Developer Dashboard

Let's do it - Edit & Publish

  1. Upload additional resources like screen shots & promotional images
  2. Pick a category and provide a detailed description
  3. Choose a price or use a freemium model
  4. Verify your website, and provide analytics token
  5. Publish!

Payments

What's up with Freemium

Transaction growth at Google

Introducing In-App Payments

Developers

  • Flat fee 5%
  • PCI Compliance
  • Risk Management
  • Simple API
  • Millions of buyers

Buyers

  • One account for payments
  • Pay with a few clicks
  • Private payment credentials

Users - click, pay, use

Developers - Monetize in two calls

API flow - Full picture

Lets integrate - Create account

  • Sign up as a seller
  • Get your Seller Id
  • Get your Seller Key
  • Configure your postback URL

Lets integrate - Define item

{
  "iss" : "1337133713371337",
  "aud" : "Google",
  "typ" : "google/payments/inapp/item/v1",
  "exp" : "1392348430",
  "iat" : "1392282180",
  "request" :{
    "name" : "Piece of Cake",
    "description" : "Virtual chocolate cake to fill your virtual tummy",
    "price" : "10.50",
    "currencyCode" : "USD",
    "sellerData" : "user_id:1224245,offer_code:3098576987"
  }
}

Lets integrate - Create JSON web token

Python:

cakeJwt = jwt.encode(item, "1ZRJNFIOSJSIDFJNVHF");

Ruby:

@cakeJwt = JWT.encode(item, "1ZRJNFIOSJSIDFJNVHF")

Lets integrate - Include JavaScript library

<script type="text/javascript" src="//www.google.com/jsapi"></script>
<script>
  google.load('payments', '1.0', {
  'packages': ['sandbox_config']
  });
</script>

Lets integrate - Define JavaScript purchase handler

function purchase() {
  ...
  goog.payments.inapp.buy({
    'jwt'     : cakeJwt,
    'success' : successHandler,
    'failure' : failureHandler
  });
}
Create purchase button
<button onclick="purchase()">Buy</button>

Lets integrate - Define postback handler

Python:

def post(self):
encoded_jwt = self.request.get('jwt', None)
if encoded_jwt is not None:
  decoded_jwt = jwt.decode(str(encoded_jwt), SELLER_SECRET)
  order_id = decoded_jwt['response']['orderId']
  self.response.out.write(order_id)
    
    

Lets integrate - Tying information together

Securing Content

Implement server side checks

Compile and minimize your JavaScript

function hello(longName) {
  alert('Hello, ' + longName);
}
hello('New User');
      
java -jar compiler.jar --js hello.js --js_output_file 
  hello-compiled.js
      
function hello(a){alert("Hello, "+a)}hello("New User");
      

Advertising

Why advertise

>250%

Overall industry growth in Q4 2010 beyond 2008 estimates

82%

Of users are willing to watch a 30 second pre-game ad

36%

Percent of all internet users are 30-day active casual gamers

AdSense for games

Ads can be shown embedded before/between game plays

Ads can be shown as a separate SWF during game load

AdSense video ads

  • Pre-Roll/Mid-Roll/Post-Roll - You determine where in the game play an ad displays
  • Ad Length - under 30 seconds
  • Contextual - based on demographics and geography
  • CPM model

AdSense Flash ads

  • Highly relevant - ads are pulled from our large advertising network leading to higher click throughs
  • Fill up to 100% of unsold inventory
  • CPC & CPM models

Reporting and controls

Report

Use AdSense reports to track your game revenue alongside your page revenue

Segment

Use channels to segment meaningful user groups and improve advertiser exposure

Filter

Use the Ad Review Center and URL filters to block unwanted advertisers

stuff

Lets integrate - Defining the ad

Import the library

import com.google.ads.instream.api.*;
      

Create an ad request

var adsRequest:AdsRequest = new AdsRequest();
// Required parameters
adsRequest.adSlotWidth = 640;
adsRequest.adSlotHeight = 360;
adsRequest.publisherId= "ca-video-afvtest";
adsRequest.adType = AdsRequestType.VIDEO;
adsRequest.contentId = "0aRIlnQzw-A";
    

Lets integrate - AdsRequest parameters

Recommended parameters

adsRequest.channels = ["sports", "entertainment", "0123456789"];
adsRequest.descriptionUrl = "http://www.example.com/description.html";
adsRequest.age = 1002;
adsRequest.gender = 1;
    

Optional parameters

adsRequest.adTest = "on";
adsRequest.language = "ja";
adsRequest.maxTotalAdDuration = 30000;
adsRequest.minTotalAdDuration = 15000;
adsRequest.uniqueAds = true;
adsRequest.adTimePosition = 1;
    

Lets integrate - AdsLoader

Prepare the adsLoader

var adsLoader:AdsLoader = new AdsLoader();
stage.addChild(adsLoader);

// ADS_LOADED for when ads are successfully returned
adsLoader.addEventListener(AdsLoadedEvent.ADS_LOADED, onAdsLoaded);

// AD_ERROR for when no ads were found for the request
adsLoader.addEventListener(AdErrorEvent.AD_ERROR, onAdError);
    

Request the ads

adsLoader.requestAds(adsRequest);
    

Lets integrate - Ad rendering

Load and render the ad

function onAdsLoaded(adsLoadedEvent:AdsLoadedEvent):void {
   // Get AdsManager
   _adsManager = adsLoadedEvent.adsManager;
   _adsManager.addEventListener(AdErrorEvent.AD_ERROR, onAdError);

   // Listen and response to events which require you to 
   // pause/resume content
   _adsManager.addEventListener(AdEvent.CONTENT_PAUSE_REQUESTED,
      onPauseRequested);
   _adsManager.addEventListener(AdEvent.CONTENT_RESUME_REQUESTED,
      onResumeRequested);
}
    

Lets integrate - Handling videos

if (_adsManager.type == AdsManagerTypes.VIDEO) {
   // Create the video ads manager.
   var videoAdsManager:VideoAdsManager = _adsManager as 
     VideoAdsManager;
   // Set a visual element on which clicks should be tracked 
   // for video ads
   videoAdsManager.clickTrackingElement = <object>;
   // Wire important events
   videoAdsManager.addEventListener(AdEvent.COMPLETE, 
     onVideoAdComplete);
   videoAdsManager.addEventListener(AdEvent.CLICK, 
     onVideoAdClicked);
   // Play back the ads.
   _adsManager.load(<flvPlayback>);
   _adsManager.play(<flvPlayback>);
}
    

Lets integrate - Handling Flash

  else if (_adsManager.type == AdsManagerTypes.FLASH) {
    // Create the flash ads manager.
    var flashAdsManager:FlashAdsManager = _adsManager as
     FlashAdsManager;

    // Play back the ad.
    flashAdsManager.load(this);
    flashAdsManager.play(this); 
  }
}

function onAdError(adErrorEvent:AdErrorEvent):void
{
  log("Ad Error: " + adErrorEvent.error);
  // Play Content
}
    

Key takeaways

Resources