diff --git a/README.md b/README.md
index aa1df68..7c3b242 100644
--- a/README.md
+++ b/README.md
@@ -13,11 +13,11 @@
   );
 ```
 
-To handle errors when something happens, like your video can't be loaded, you can pass a callback with a prop `onError` in the component:
+To handle errors, you can pass a function to the `onError` prop:
 
-```javascript
+```js
   function onError(err) {
-    console.log(err);
+    console.error(err);
   };
 
   React.render(
@@ -26,8 +26,6 @@ To handle errors when something happens, like your video can't be loaded, you ca
   );
 ```
 
-If you decide to use just Javascript without any module loader, you can get the global variable `window.ReactVimeo` *(or just `ReactVimeo`)*:
-
 ## Behind the Scene
 
 There are some things that you should know about the component. The first one is the structure created inside by the component if you wish to stylize it.
@@ -50,30 +48,13 @@ So, the semantic HTML structure will be something like this:
   </div>
 ```
 
-This is a very simple structure to stylize however you want. So, if you are lost, don't panic, there is a [real functional example](/example) that you can follow.
-
-For more details, check out the API below.
-
-## Component API
-
-`<Vimeo>` component:
+This is a very simple structure to stylize however you want. So, if you are lost, don't panic, there is a [real functional example](/index.html) that you can follow.
 
-Property | Type | Default | Required | Description
--------- | ---- | ------- | -------- |-----------
-className | string | 'vimeo' | no | className applied to wrapping div
-onCuechange | func | noop | no | called when the player que changes
-onError | func | noop | no | called if the video metadata (thumbnail) can't be loaded
-onFinish | func | noop | no | called when video completes
-onLoadProgress | func | noop | no | called when part of video has loaded
-onPause | func | noop | no | called when video is paused
-onPlay | func | noop | no | called when video is played
-onPlayProgress | func | noop | no | called when video play has progressed
-onReady | func | noop | no | called when video has loaded and is ready to play. other event functions will not be called before this one other than onError 
-onSeek | func | noop | no | called when user seeks ahead in video
-videoId | string | none | yes | The vimeo ID
+For more details, check out the API
 
-Interactive api (play/pause actions, seek to `n`, etc..) to come in future versions
+## API
 
+[API](docs/README.md)
 
 ## License
 
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..0b11b00
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,56 @@
+
+# API
+
+```js
+Interface props {
+    videoId: String,
+    className?: String = 'vimeo',
+    onReady?(data?: Object) => Void,
+    onCuechange?(data?: Object) => Void,
+    onError?(data?: Object) => Void,
+    onFinish?(data?: Object) => Void,
+    onLoadProgress?(data?: Object) => Void,
+    onPause?(data?: Object) => Void,
+    onPlay?(data?: Object) => Void,
+    onPlayProgress?(data?: Object) => Void,
+    onSeek?(data?: Object) => Void
+};
+```
+
+## videoId: String
+The Vimeo video ID
+
+## className: String
+`className` applied to wrapping div
+
+## onReady?(data: Object) => Void
+Called when video has loaded and is ready to play.
+Other event functions will not be called before this one other than onError
+
+
+## onCuechange?(data: Object) => Void
+Called when the player que changes.
+
+## onError?(data: Object) => Void
+Called in the event that there is an error.
+If no error handler provided, the error will be thrown.
+
+## onFinish?(data: Object) => Void
+Called when video completes
+
+## onLoadProgress?(data: Object) => Void
+Called when part of video has loaded
+
+## onPause?(data: Object) => Void
+Called when video is paused
+
+## onPlay?(data: Object) => Void
+Called when video is played
+
+## onPlayProgress?(data: Object) => Void
+Called when video play has progressed
+
+## onSeek?(data: Object) => Void
+Called when user seeks ahead in video
+
+Interactive api (play/pause actions, seek to `n`, etc..) to come in future versions
diff --git a/example/index.html b/example/index.html
deleted file mode 100644
index 793aca5..0000000
--- a/example/index.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <title>Example | React Video</title>
-    <link rel="stylesheet" href="http://necolas.github.io/normalize.css/3.0.1/normalize.css">
-    <link rel="stylesheet" href="react-video.css">
-    <style>
-      @media screen and (min-width: 600px) {
-        .content {
-          width: 100%;
-        }
-      }
-
-      @media screen and (min-width: 960px) {
-        .content {
-          width: 70%;
-        }
-      }
-
-      #video-youtube,
-      #video-vimeo {
-        width: 80%;
-        margin: 50px;
-      }
-    </style>
-  </head>
-  <body>
-    <div class="content">
-      <div id="vimeo"></div>
-    </div>
-
-    <script src="//cdnjs.cloudflare.com/ajax/libs/react/0.13.3/react.js"></script>
-    <script src="vimeo.js"></script>
-    <script type="text/javascript">
-      React.render(
-        React.createElement(ReactVimeo, { videoId: '108843586' }),
-        document.getElementById('vimeo')
-      );
-    </script>
-  </body>
-</html>
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..9a41198
--- /dev/null
+++ b/index.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>Example | React Video</title>
+    <link rel="stylesheet" href="http://necolas.github.io/normalize.css/3.0.1/normalize.css">
+    <link rel="stylesheet" href="/lib/Vimeo.css">
+    <style>
+      @media screen and (min-width: 600px) {
+        .content {
+          width: 100%;
+        }
+      }
+
+      @media screen and (min-width: 960px) {
+        .content {
+          width: 70%;
+        }
+      }
+
+      #vimeo {
+        width: 80%;
+        margin: 50px;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="content">
+      <div id="vimeo"></div>
+    </div>
+
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react-dom.js"></script>
+    <script src="/lib/umd/ReactVimeo.js"></script>
+    <script type="text/javascript">
+      ReactDOM.render(
+        React.createElement(ReactVimeo, { videoId: '131196784' }),
+        document.getElementById('vimeo')
+      );
+    </script>
+  </body>
+</html>
diff --git a/lib/umd/ReactVimeo.js b/lib/umd/ReactVimeo.js
index 4523167..26235d9 100644
--- a/lib/umd/ReactVimeo.js
+++ b/lib/umd/ReactVimeo.js
@@ -1,6 +1,6 @@
 /*
  * React-Vimeo - React component to load video from Vimeo
- * @version v0.0.3
+ * @version v0.1.0
  * @link https://github.com/freecodecamp/react-vimeo
  * @license MIT
  * @author Berkeley Martinez (https://github.com/berkeleytrue)
@@ -74,24 +74,26 @@ return /******/ (function(modules) { // webpackBootstrap
 
 	var _react2 = _interopRequireDefault(_react);
 
-	var _keymirror = __webpack_require__(8);
+	var _keymirror = __webpack_require__(11);
 
 	var _keymirror2 = _interopRequireDefault(_keymirror);
 
-	var _debug = __webpack_require__(2);
+	var _jsonp = __webpack_require__(7);
+
+	var _jsonp2 = _interopRequireDefault(_jsonp);
+
+	var _debug = __webpack_require__(4);
 
 	var _debug2 = _interopRequireDefault(_debug);
 
-	var _PlayButton = __webpack_require__(3);
+	var _PlayButton = __webpack_require__(2);
 
 	var _PlayButton2 = _interopRequireDefault(_PlayButton);
 
-	var _Spinner = __webpack_require__(4);
+	var _Spinner = __webpack_require__(3);
 
 	var _Spinner2 = _interopRequireDefault(_Spinner);
 
-	var _ajax = __webpack_require__(5);
-
 	var debug = (0, _debug2['default'])('vimeo:player');
 	var noop = function noop() {};
 	var playerEvents = (0, _keymirror2['default'])({
@@ -109,12 +111,16 @@ return /******/ (function(modules) { // webpackBootstrap
 	}
 
 	function getFuncForEvent(event, props) {
-	  return props['on' + capitalize(event)];
+	  return props['on' + capitalize(event)] || function () {};
 	}
 
 	function post(method, value, player, playerOrigin) {
-	  player.contentWindow.postMessage({ method: method, value: value }, playerOrigin);
-	  return player;
+	  try {
+	    player.contentWindow.postMessage({ method: method, value: value }, playerOrigin);
+	  } catch (err) {
+	    return err;
+	  }
+	  return null;
 	}
 
 	exports['default'] = _react2['default'].createClass({
@@ -185,6 +191,13 @@ return /******/ (function(modules) { // webpackBootstrap
 	    addEventListener('message', this.onMessage);
 	  },
 
+	  onError: function onError(err) {
+	    if (this.props.onError) {
+	      this.props.onError(err);
+	    }
+	    throw err;
+	  },
+
 	  onMessage: function onMessage(e) {
 	    var onReady = this.props.onReady;
 	    var playerOrigin = this.state.playerOrigin;
@@ -200,25 +213,33 @@ return /******/ (function(modules) { // webpackBootstrap
 	      return false;
 	    }
 
-	    var dats = JSON.parse(e.data);
+	    var dats = undefined;
+	    try {
+	      dats = JSON.parse(e.data);
+	    } catch (err) {
+	      debug('error parsing message', err);
+	      dats = {};
+	    }
 
 	    if (dats.event === 'ready') {
-	      var player = _react2['default'].findDOMNode(this.refs.player);
+	      var player = this.refs.player;
+
 	      debug('player ready');
 	      this.onReady(player, playerOrigin === '*' ? e.origin : playerOrigin);
 	      return onReady(dats);
 	    }
 
-	    var potentialFunc = getFuncForEvent(dats.event, this.props);
-
-	    if (typeof potentialFunc === 'function') {
-	      potentialFunc(dats);
-	    }
+	    getFuncForEvent(dats.event, this.props)(dats);
 	  },
 
 	  onReady: function onReady(player, playerOrigin) {
+	    var _this = this;
+
 	    Object.keys(playerEvents).forEach(function (event) {
-	      post('addEventListener', event, player, playerOrigin);
+	      var err = post('addEventListener', event, player, playerOrigin);
+	      if (err) {
+	        _this.onError(err);
+	      }
 	    });
 	  },
 
@@ -232,23 +253,25 @@ return /******/ (function(modules) { // webpackBootstrap
 	  },
 
 	  fetchVimeoData: function fetchVimeoData() {
-	    var _this = this;
+	    var _this2 = this;
 
 	    if (this.state.imageLoaded) {
 	      return;
 	    }
 	    var id = this.props.videoId;
 
-	    (0, _ajax.get)({
-	      url: '//vimeo.com/api/v2/video/' + id + '.json',
-	      onSuccess: function onSuccess(res) {
-	        debug('ajax response', res);
-	        _this.setState({
-	          thumb: res[0].thumbnail_large,
-	          imageLoaded: true
-	        });
-	      },
-	      onError: this.props.onError || function () {}
+	    (0, _jsonp2['default'])('//vimeo.com/api/v2/video/' + id + '.json', {
+	      prefix: 'vimeo'
+	    }, function (err, res) {
+	      if (err) {
+	        debug('jsonp err: ', err.message);
+	        _this2.onError(err);
+	      }
+	      debug('jsonp response', res);
+	      _this2.setState({
+	        thumb: res[0].thumbnail_large,
+	        imageLoaded: true
+	      });
 	    });
 	  },
 
@@ -330,6 +353,91 @@ return /******/ (function(modules) { // webpackBootstrap
 /* 2 */
 /***/ function(module, exports, __webpack_require__) {
 
+	/* eslint-disable max-len */
+	'use strict';
+
+	Object.defineProperty(exports, '__esModule', {
+	  value: true
+	});
+
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+	var _react = __webpack_require__(1);
+
+	var _react2 = _interopRequireDefault(_react);
+
+	exports['default'] = _react2['default'].createClass({
+	  displayName: 'PlayButton',
+
+	  propTypes: {
+	    onClick: _react2['default'].PropTypes.func
+	  },
+
+	  render: function render() {
+	    return _react2['default'].createElement(
+	      'button',
+	      {
+	        className: 'vimeo-play-button',
+	        onClick: this.props.onClick,
+	        type: 'button' },
+	      _react2['default'].createElement(
+	        'svg',
+	        {
+	          version: '1.1',
+	          viewBox: '0 0 100 100',
+	          xmlns: 'http://www.w3.org/2000/svg' },
+	        _react2['default'].createElement('path', { d: 'M79.674,53.719c2.59-2.046,2.59-5.392,0-7.437L22.566,1.053C19.977-0.993,18,0.035,18,3.335v93.331c0,3.3,1.977,4.326,4.566,2.281L79.674,53.719z' })
+	      )
+	    );
+	  }
+	});
+	module.exports = exports['default'];
+
+/***/ },
+/* 3 */
+/***/ function(module, exports, __webpack_require__) {
+
+	/* eslint-disable max-len */
+	'use strict';
+
+	Object.defineProperty(exports, '__esModule', {
+	  value: true
+	});
+
+	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+	var _react = __webpack_require__(1);
+
+	var _react2 = _interopRequireDefault(_react);
+
+	exports['default'] = _react2['default'].createClass({
+	  displayName: 'Spinner',
+
+	  render: function render() {
+	    return _react2['default'].createElement(
+	      'div',
+	      { className: 'vimeo-loading' },
+	      _react2['default'].createElement(
+	        'svg',
+	        {
+	          height: '32',
+	          viewBox: '0 0 32 32',
+	          width: '32',
+	          xmlns: 'http://www.w3.org/2000/svg' },
+	        _react2['default'].createElement('path', {
+	          d: 'M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4',
+	          opacity: '.25' }),
+	        _react2['default'].createElement('path', { d: 'M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z' })
+	      )
+	    );
+	  }
+	});
+	module.exports = exports['default'];
+
+/***/ },
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
 	
 	/**
 	 * This is the web browser implementation of `debug()`.
@@ -337,7 +445,7 @@ return /******/ (function(modules) { // webpackBootstrap
 	 * Expose `debug()` as the module.
 	 */
 
-	exports = module.exports = __webpack_require__(6);
+	exports = module.exports = __webpack_require__(5);
 	exports.log = log;
 	exports.formatArgs = formatArgs;
 	exports.save = save;
@@ -501,154 +609,9 @@ return /******/ (function(modules) { // webpackBootstrap
 
 
 /***/ },
-/* 3 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* eslint-disable max-len */
-	'use strict';
-
-	Object.defineProperty(exports, '__esModule', {
-	  value: true
-	});
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-	var _react = __webpack_require__(1);
-
-	var _react2 = _interopRequireDefault(_react);
-
-	exports['default'] = _react2['default'].createClass({
-	  displayName: 'PlayButton',
-
-	  propTypes: {
-	    onClick: _react2['default'].PropTypes.func
-	  },
-
-	  render: function render() {
-	    return _react2['default'].createElement(
-	      'button',
-	      {
-	        className: 'vimeo-play-button',
-	        onClick: this.props.onClick,
-	        type: 'button' },
-	      _react2['default'].createElement(
-	        'svg',
-	        {
-	          version: '1.1',
-	          viewBox: '0 0 100 100',
-	          xmlns: 'http://www.w3.org/2000/svg' },
-	        _react2['default'].createElement('path', { d: 'M79.674,53.719c2.59-2.046,2.59-5.392,0-7.437L22.566,1.053C19.977-0.993,18,0.035,18,3.335v93.331c0,3.3,1.977,4.326,4.566,2.281L79.674,53.719z' })
-	      )
-	    );
-	  }
-	});
-	module.exports = exports['default'];
-
-/***/ },
-/* 4 */
-/***/ function(module, exports, __webpack_require__) {
-
-	/* eslint-disable max-len */
-	'use strict';
-
-	Object.defineProperty(exports, '__esModule', {
-	  value: true
-	});
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-	var _react = __webpack_require__(1);
-
-	var _react2 = _interopRequireDefault(_react);
-
-	exports['default'] = _react2['default'].createClass({
-	  displayName: 'Spinner',
-
-	  render: function render() {
-	    return _react2['default'].createElement(
-	      'div',
-	      { className: 'vimeo-loading' },
-	      _react2['default'].createElement(
-	        'svg',
-	        {
-	          height: '32',
-	          viewBox: '0 0 32 32',
-	          width: '32',
-	          xmlns: 'http://www.w3.org/2000/svg' },
-	        _react2['default'].createElement('path', {
-	          d: 'M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4',
-	          opacity: '.25' }),
-	        _react2['default'].createElement('path', { d: 'M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z' })
-	      )
-	    );
-	  }
-	});
-	module.exports = exports['default'];
-
-/***/ },
 /* 5 */
 /***/ function(module, exports, __webpack_require__) {
 
-	'use strict';
-
-	Object.defineProperty(exports, '__esModule', {
-	  value: true
-	});
-	exports.get = get;
-
-	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-	var _debug = __webpack_require__(2);
-
-	var _debug2 = _interopRequireDefault(_debug);
-
-	var errMessage = { error: 'Sorry, an error occurred on the server' };
-	var debug = (0, _debug2['default'])('vimeo:ajax');
-
-	function get(opts) {
-	  var url = opts.url;
-	  var onSuccess = opts.onSuccess;
-	  var onError = opts.onError;
-	  var req = undefined;
-
-	  try {
-	    req = new XMLHttpRequest();
-	  } catch (e) {
-	    req = new XDomainRequest();
-	  }
-
-	  // XDomainRequest onload
-	  // ie 8-9 support
-	  function oldIE() {
-	    onSuccess(JSON.parse(req.responseText));
-	  }
-
-	  // XMLHttpRequest onload
-	  function onReadyStateChange() {
-	    if (req.readyState !== 4 || req.status !== 200) {
-	      return;
-	    }
-	    return onSuccess(JSON.parse(req.responseText));
-	  }
-
-	  function errHandler(err) {
-	    debug('error occured fetching video data', err);
-	    return onError(errMessage);
-	  }
-
-	  req.onreadystatechange = onReadyStateChange;
-	  req.onload = oldIE;
-	  req.onerror = errHandler;
-	  req.open('GET', url, true);
-	  req.send();
-
-	  return req.abort.bind(req);
-	}
-
-/***/ },
-/* 6 */
-/***/ function(module, exports, __webpack_require__) {
-
 	
 	/**
 	 * This is the common logic for both the Node.js and web browser
@@ -662,7 +625,7 @@ return /******/ (function(modules) { // webpackBootstrap
 	exports.disable = disable;
 	exports.enable = enable;
 	exports.enabled = enabled;
-	exports.humanize = __webpack_require__(7);
+	exports.humanize = __webpack_require__(6);
 
 	/**
 	 * The currently active debug mode names, and names to skip.
@@ -849,7 +812,7 @@ return /******/ (function(modules) { // webpackBootstrap
 
 
 /***/ },
-/* 7 */
+/* 6 */
 /***/ function(module, exports) {
 
 	/**
@@ -980,7 +943,623 @@ return /******/ (function(modules) { // webpackBootstrap
 
 
 /***/ },
-/* 8 */
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+	/**
+	 * Module dependencies
+	 */
+
+	var debug = __webpack_require__(8)('jsonp');
+
+	/**
+	 * Module exports.
+	 */
+
+	module.exports = jsonp;
+
+	/**
+	 * Callback index.
+	 */
+
+	var count = 0;
+
+	/**
+	 * Noop function.
+	 */
+
+	function noop(){}
+
+	/**
+	 * JSONP handler
+	 *
+	 * Options:
+	 *  - param {String} qs parameter (`callback`)
+	 *  - prefix {String} qs parameter (`__jp`)
+	 *  - name {String} qs parameter (`prefix` + incr)
+	 *  - timeout {Number} how long after a timeout error is emitted (`60000`)
+	 *
+	 * @param {String} url
+	 * @param {Object|Function} optional options / callback
+	 * @param {Function} optional callback
+	 */
+
+	function jsonp(url, opts, fn){
+	  if ('function' == typeof opts) {
+	    fn = opts;
+	    opts = {};
+	  }
+	  if (!opts) opts = {};
+
+	  var prefix = opts.prefix || '__jp';
+
+	  // use the callback name that was passed if one was provided.
+	  // otherwise generate a unique name by incrementing our counter.
+	  var id = opts.name || (prefix + (count++));
+
+	  var param = opts.param || 'callback';
+	  var timeout = null != opts.timeout ? opts.timeout : 60000;
+	  var enc = encodeURIComponent;
+	  var target = document.getElementsByTagName('script')[0] || document.head;
+	  var script;
+	  var timer;
+
+
+	  if (timeout) {
+	    timer = setTimeout(function(){
+	      cleanup();
+	      if (fn) fn(new Error('Timeout'));
+	    }, timeout);
+	  }
+
+	  function cleanup(){
+	    if (script.parentNode) script.parentNode.removeChild(script);
+	    window[id] = noop;
+	    if (timer) clearTimeout(timer);
+	  }
+
+	  function cancel(){
+	    if (window[id]) {
+	      cleanup();
+	    }
+	  }
+
+	  window[id] = function(data){
+	    debug('jsonp got', data);
+	    cleanup();
+	    if (fn) fn(null, data);
+	  };
+
+	  // add qs component
+	  url += (~url.indexOf('?') ? '&' : '?') + param + '=' + enc(id);
+	  url = url.replace('?&', '?');
+
+	  debug('jsonp req "%s"', url);
+
+	  // create script
+	  script = document.createElement('script');
+	  script.src = url;
+	  target.parentNode.insertBefore(script, target);
+
+	  return cancel;
+	}
+
+
+/***/ },
+/* 8 */
+/***/ function(module, exports, __webpack_require__) {
+
+	
+	/**
+	 * This is the web browser implementation of `debug()`.
+	 *
+	 * Expose `debug()` as the module.
+	 */
+
+	exports = module.exports = __webpack_require__(9);
+	exports.log = log;
+	exports.formatArgs = formatArgs;
+	exports.save = save;
+	exports.load = load;
+	exports.useColors = useColors;
+
+	/**
+	 * Use chrome.storage.local if we are in an app
+	 */
+
+	var storage;
+
+	if (typeof chrome !== 'undefined' && typeof chrome.storage !== 'undefined')
+	  storage = chrome.storage.local;
+	else
+	  storage = localstorage();
+
+	/**
+	 * Colors.
+	 */
+
+	exports.colors = [
+	  'lightseagreen',
+	  'forestgreen',
+	  'goldenrod',
+	  'dodgerblue',
+	  'darkorchid',
+	  'crimson'
+	];
+
+	/**
+	 * Currently only WebKit-based Web Inspectors, Firefox >= v31,
+	 * and the Firebug extension (any Firefox version) are known
+	 * to support "%c" CSS customizations.
+	 *
+	 * TODO: add a `localStorage` variable to explicitly enable/disable colors
+	 */
+
+	function useColors() {
+	  // is webkit? http://stackoverflow.com/a/16459606/376773
+	  return ('WebkitAppearance' in document.documentElement.style) ||
+	    // is firebug? http://stackoverflow.com/a/398120/376773
+	    (window.console && (console.firebug || (console.exception && console.table))) ||
+	    // is firefox >= v31?
+	    // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
+	    (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
+	}
+
+	/**
+	 * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
+	 */
+
+	exports.formatters.j = function(v) {
+	  return JSON.stringify(v);
+	};
+
+
+	/**
+	 * Colorize log arguments if enabled.
+	 *
+	 * @api public
+	 */
+
+	function formatArgs() {
+	  var args = arguments;
+	  var useColors = this.useColors;
+
+	  args[0] = (useColors ? '%c' : '')
+	    + this.namespace
+	    + (useColors ? ' %c' : ' ')
+	    + args[0]
+	    + (useColors ? '%c ' : ' ')
+	    + '+' + exports.humanize(this.diff);
+
+	  if (!useColors) return args;
+
+	  var c = 'color: ' + this.color;
+	  args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
+
+	  // the final "%c" is somewhat tricky, because there could be other
+	  // arguments passed either before or after the %c, so we need to
+	  // figure out the correct index to insert the CSS into
+	  var index = 0;
+	  var lastC = 0;
+	  args[0].replace(/%[a-z%]/g, function(match) {
+	    if ('%%' === match) return;
+	    index++;
+	    if ('%c' === match) {
+	      // we only are interested in the *last* %c
+	      // (the user may have provided their own)
+	      lastC = index;
+	    }
+	  });
+
+	  args.splice(lastC, 0, c);
+	  return args;
+	}
+
+	/**
+	 * Invokes `console.log()` when available.
+	 * No-op when `console.log` is not a "function".
+	 *
+	 * @api public
+	 */
+
+	function log() {
+	  // this hackery is required for IE8/9, where
+	  // the `console.log` function doesn't have 'apply'
+	  return 'object' === typeof console
+	    && console.log
+	    && Function.prototype.apply.call(console.log, console, arguments);
+	}
+
+	/**
+	 * Save `namespaces`.
+	 *
+	 * @param {String} namespaces
+	 * @api private
+	 */
+
+	function save(namespaces) {
+	  try {
+	    if (null == namespaces) {
+	      storage.removeItem('debug');
+	    } else {
+	      storage.debug = namespaces;
+	    }
+	  } catch(e) {}
+	}
+
+	/**
+	 * Load `namespaces`.
+	 *
+	 * @return {String} returns the previously persisted debug modes
+	 * @api private
+	 */
+
+	function load() {
+	  var r;
+	  try {
+	    r = storage.debug;
+	  } catch(e) {}
+	  return r;
+	}
+
+	/**
+	 * Enable namespaces listed in `localStorage.debug` initially.
+	 */
+
+	exports.enable(load());
+
+	/**
+	 * Localstorage attempts to return the localstorage.
+	 *
+	 * This is necessary because safari throws
+	 * when a user disables cookies/localstorage
+	 * and you attempt to access it.
+	 *
+	 * @return {LocalStorage}
+	 * @api private
+	 */
+
+	function localstorage(){
+	  try {
+	    return window.localStorage;
+	  } catch (e) {}
+	}
+
+
+/***/ },
+/* 9 */
+/***/ function(module, exports, __webpack_require__) {
+
+	
+	/**
+	 * This is the common logic for both the Node.js and web browser
+	 * implementations of `debug()`.
+	 *
+	 * Expose `debug()` as the module.
+	 */
+
+	exports = module.exports = debug;
+	exports.coerce = coerce;
+	exports.disable = disable;
+	exports.enable = enable;
+	exports.enabled = enabled;
+	exports.humanize = __webpack_require__(10);
+
+	/**
+	 * The currently active debug mode names, and names to skip.
+	 */
+
+	exports.names = [];
+	exports.skips = [];
+
+	/**
+	 * Map of special "%n" handling functions, for the debug "format" argument.
+	 *
+	 * Valid key names are a single, lowercased letter, i.e. "n".
+	 */
+
+	exports.formatters = {};
+
+	/**
+	 * Previously assigned color.
+	 */
+
+	var prevColor = 0;
+
+	/**
+	 * Previous log timestamp.
+	 */
+
+	var prevTime;
+
+	/**
+	 * Select a color.
+	 *
+	 * @return {Number}
+	 * @api private
+	 */
+
+	function selectColor() {
+	  return exports.colors[prevColor++ % exports.colors.length];
+	}
+
+	/**
+	 * Create a debugger with the given `namespace`.
+	 *
+	 * @param {String} namespace
+	 * @return {Function}
+	 * @api public
+	 */
+
+	function debug(namespace) {
+
+	  // define the `disabled` version
+	  function disabled() {
+	  }
+	  disabled.enabled = false;
+
+	  // define the `enabled` version
+	  function enabled() {
+
+	    var self = enabled;
+
+	    // set `diff` timestamp
+	    var curr = +new Date();
+	    var ms = curr - (prevTime || curr);
+	    self.diff = ms;
+	    self.prev = prevTime;
+	    self.curr = curr;
+	    prevTime = curr;
+
+	    // add the `color` if not set
+	    if (null == self.useColors) self.useColors = exports.useColors();
+	    if (null == self.color && self.useColors) self.color = selectColor();
+
+	    var args = Array.prototype.slice.call(arguments);
+
+	    args[0] = exports.coerce(args[0]);
+
+	    if ('string' !== typeof args[0]) {
+	      // anything else let's inspect with %o
+	      args = ['%o'].concat(args);
+	    }
+
+	    // apply any `formatters` transformations
+	    var index = 0;
+	    args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
+	      // if we encounter an escaped % then don't increase the array index
+	      if (match === '%%') return match;
+	      index++;
+	      var formatter = exports.formatters[format];
+	      if ('function' === typeof formatter) {
+	        var val = args[index];
+	        match = formatter.call(self, val);
+
+	        // now we need to remove `args[index]` since it's inlined in the `format`
+	        args.splice(index, 1);
+	        index--;
+	      }
+	      return match;
+	    });
+
+	    if ('function' === typeof exports.formatArgs) {
+	      args = exports.formatArgs.apply(self, args);
+	    }
+	    var logFn = enabled.log || exports.log || console.log.bind(console);
+	    logFn.apply(self, args);
+	  }
+	  enabled.enabled = true;
+
+	  var fn = exports.enabled(namespace) ? enabled : disabled;
+
+	  fn.namespace = namespace;
+
+	  return fn;
+	}
+
+	/**
+	 * Enables a debug mode by namespaces. This can include modes
+	 * separated by a colon and wildcards.
+	 *
+	 * @param {String} namespaces
+	 * @api public
+	 */
+
+	function enable(namespaces) {
+	  exports.save(namespaces);
+
+	  var split = (namespaces || '').split(/[\s,]+/);
+	  var len = split.length;
+
+	  for (var i = 0; i < len; i++) {
+	    if (!split[i]) continue; // ignore empty strings
+	    namespaces = split[i].replace(/\*/g, '.*?');
+	    if (namespaces[0] === '-') {
+	      exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
+	    } else {
+	      exports.names.push(new RegExp('^' + namespaces + '$'));
+	    }
+	  }
+	}
+
+	/**
+	 * Disable debug output.
+	 *
+	 * @api public
+	 */
+
+	function disable() {
+	  exports.enable('');
+	}
+
+	/**
+	 * Returns true if the given mode name is enabled, false otherwise.
+	 *
+	 * @param {String} name
+	 * @return {Boolean}
+	 * @api public
+	 */
+
+	function enabled(name) {
+	  var i, len;
+	  for (i = 0, len = exports.skips.length; i < len; i++) {
+	    if (exports.skips[i].test(name)) {
+	      return false;
+	    }
+	  }
+	  for (i = 0, len = exports.names.length; i < len; i++) {
+	    if (exports.names[i].test(name)) {
+	      return true;
+	    }
+	  }
+	  return false;
+	}
+
+	/**
+	 * Coerce `val`.
+	 *
+	 * @param {Mixed} val
+	 * @return {Mixed}
+	 * @api private
+	 */
+
+	function coerce(val) {
+	  if (val instanceof Error) return val.stack || val.message;
+	  return val;
+	}
+
+
+/***/ },
+/* 10 */
+/***/ function(module, exports) {
+
+	/**
+	 * Helpers.
+	 */
+
+	var s = 1000;
+	var m = s * 60;
+	var h = m * 60;
+	var d = h * 24;
+	var y = d * 365.25;
+
+	/**
+	 * Parse or format the given `val`.
+	 *
+	 * Options:
+	 *
+	 *  - `long` verbose formatting [false]
+	 *
+	 * @param {String|Number} val
+	 * @param {Object} options
+	 * @return {String|Number}
+	 * @api public
+	 */
+
+	module.exports = function(val, options){
+	  options = options || {};
+	  if ('string' == typeof val) return parse(val);
+	  return options.long
+	    ? long(val)
+	    : short(val);
+	};
+
+	/**
+	 * Parse the given `str` and return milliseconds.
+	 *
+	 * @param {String} str
+	 * @return {Number}
+	 * @api private
+	 */
+
+	function parse(str) {
+	  var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);
+	  if (!match) return;
+	  var n = parseFloat(match[1]);
+	  var type = (match[2] || 'ms').toLowerCase();
+	  switch (type) {
+	    case 'years':
+	    case 'year':
+	    case 'yrs':
+	    case 'yr':
+	    case 'y':
+	      return n * y;
+	    case 'days':
+	    case 'day':
+	    case 'd':
+	      return n * d;
+	    case 'hours':
+	    case 'hour':
+	    case 'hrs':
+	    case 'hr':
+	    case 'h':
+	      return n * h;
+	    case 'minutes':
+	    case 'minute':
+	    case 'mins':
+	    case 'min':
+	    case 'm':
+	      return n * m;
+	    case 'seconds':
+	    case 'second':
+	    case 'secs':
+	    case 'sec':
+	    case 's':
+	      return n * s;
+	    case 'milliseconds':
+	    case 'millisecond':
+	    case 'msecs':
+	    case 'msec':
+	    case 'ms':
+	      return n;
+	  }
+	}
+
+	/**
+	 * Short format for `ms`.
+	 *
+	 * @param {Number} ms
+	 * @return {String}
+	 * @api private
+	 */
+
+	function short(ms) {
+	  if (ms >= d) return Math.round(ms / d) + 'd';
+	  if (ms >= h) return Math.round(ms / h) + 'h';
+	  if (ms >= m) return Math.round(ms / m) + 'm';
+	  if (ms >= s) return Math.round(ms / s) + 's';
+	  return ms + 'ms';
+	}
+
+	/**
+	 * Long format for `ms`.
+	 *
+	 * @param {Number} ms
+	 * @return {String}
+	 * @api private
+	 */
+
+	function long(ms) {
+	  return plural(ms, d, 'day')
+	    || plural(ms, h, 'hour')
+	    || plural(ms, m, 'minute')
+	    || plural(ms, s, 'second')
+	    || ms + ' ms';
+	}
+
+	/**
+	 * Pluralization helper.
+	 */
+
+	function plural(ms, n, name) {
+	  if (ms < n) return;
+	  if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
+	  return Math.ceil(ms / n) + ' ' + name + 's';
+	}
+
+
+/***/ },
+/* 11 */
 /***/ function(module, exports) {
 
 	/**
diff --git a/lib/umd/ReactVimeo.min.js b/lib/umd/ReactVimeo.min.js
index dfb1aa3..e4b6203 100644
--- a/lib/umd/ReactVimeo.min.js
+++ b/lib/umd/ReactVimeo.min.js
@@ -1,8 +1,8 @@
 /*
  * React-Vimeo - React component to load video from Vimeo
- * @version v0.0.3
+ * @version v0.1.0
  * @link https://github.com/freecodecamp/react-vimeo
  * @license MIT
  * @author Berkeley Martinez (https://github.com/berkeleytrue)
 */
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.ReactVimeo=t(require("react")):e.ReactVimeo=t(e.React)}(this,function(e){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function o(e){return e.charAt(0).toUpperCase()+e.substring(1)}function s(e,t){return t["on"+o(e)]}function a(e,t,n,r){return n.contentWindow.postMessage({method:e,value:t},r),n}Object.defineProperty(t,"__esModule",{value:!0});var i=n(1),c=r(i),u=n(8),l=r(u),d=n(2),f=r(d),p=n(3),m=r(p),h=n(4),g=r(h),y=n(5),v=f["default"]("vimeo:player"),w=function(){},b=l["default"]({cuechange:null,finish:null,loadProgress:null,pause:null,play:null,playProgress:null,seek:null});t["default"]=c["default"].createClass({displayName:"Vimeo",propTypes:{className:i.PropTypes.string,loading:i.PropTypes.element,onCuechange:i.PropTypes.func,onError:i.PropTypes.func,onFinish:i.PropTypes.func,onLoadProgress:i.PropTypes.func,onPause:i.PropTypes.func,onPlay:i.PropTypes.func,onPlayProgress:i.PropTypes.func,onReady:i.PropTypes.func,onSeek:i.PropTypes.func,playButton:i.PropTypes.node,videoId:i.PropTypes.string.isRequired},getDefaultProps:function(){var e=Object.keys(b).concat(["ready"]).reduce(function(e,t){return e["on"+o(t)]=w,e},{});return e.className="vimeo",e},getInitialState:function(){return{imageLoaded:!1,playerOrigin:"*",showingVideo:!1,thumb:null}},componentWillReceiveProps:function(e){e.videoId!==this.props.videoId&&this.setState({thumb:null,imageLoaded:!1,showingVideo:!1})},componentDidMount:function(){this.fetchVimeoData()},componentDidUpdate:function(){this.fetchVimeoData()},componentWillUnmount:function(){var e="undefined"!=typeof window?window.removeEventListener.bind(window):w;e("message",this.onMessage)},addMessageListener:function(){var e="undefined"!=typeof window?window.addEventListener.bind(window):w;e("message",this.onMessage)},onMessage:function(e){var t=this.props.onReady,n=this.state.playerOrigin;if("*"===n&&this.setState({playerOrigin:e.origin}),!/^https?:\/\/player.vimeo.com/.test(e.origin))return!1;var r=JSON.parse(e.data);if("ready"===r.event){var o=c["default"].findDOMNode(this.refs.player);return v("player ready"),this.onReady(o,"*"===n?e.origin:n),t(r)}var a=s(r.event,this.props);"function"==typeof a&&a(r)},onReady:function(e,t){Object.keys(b).forEach(function(n){a("addEventListener",n,e,t)})},playVideo:function(e){e.preventDefault(),this.setState({showingVideo:!0})},getIframeUrl:function(){return"//player.vimeo.com/video/"+this.props.videoId+"?autoplay=1"},fetchVimeoData:function(){var e=this;if(!this.state.imageLoaded){var t=this.props.videoId;y.get({url:"//vimeo.com/api/v2/video/"+t+".json",onSuccess:function(t){v("ajax response",t),e.setState({thumb:t[0].thumbnail_large,imageLoaded:!0})},onError:this.props.onError||function(){}})}},renderImage:function(){if(!this.state.showingVideo&&this.state.imageLoaded){var e={backgroundImage:"url("+this.state.thumb+")",display:this.state.showingVideo?"none":"block",height:"100%",width:"100%"};return c["default"].createElement("div",{className:"vimeo-image",style:e},c["default"].createElement(m["default"],{onClick:this.playVideo}))}},renderIframe:function(){if(this.state.showingVideo){this.addMessageListener();var e={display:this.state.showingVideo?"block":"none",height:"100%",width:"100%"};return c["default"].createElement("div",{className:"vimeo-embed",style:e},c["default"].createElement("iframe",{frameBorder:"0",ref:"player",src:this.getIframeUrl()}))}},renderLoading:function(e,t){return e?void 0:t?t:c["default"].createElement(g["default"],null)},render:function(){return c["default"].createElement("div",{className:this.props.className},this.renderLoading(this.state.imageLoaded,this.props.loading),this.renderImage(),this.renderIframe())}}),e.exports=t["default"]},function(t,n){t.exports=e},function(e,t,n){function r(){return"WebkitAppearance"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31}function o(){var e=arguments,n=this.useColors;if(e[0]=(n?"%c":"")+this.namespace+(n?" %c":" ")+e[0]+(n?"%c ":" ")+"+"+t.humanize(this.diff),!n)return e;var r="color: "+this.color;e=[e[0],r,"color: inherit"].concat(Array.prototype.slice.call(e,1));var o=0,s=0;return e[0].replace(/%[a-z%]/g,function(e){"%%"!==e&&(o++,"%c"===e&&(s=o))}),e.splice(s,0,r),e}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?t.storage.removeItem("debug"):t.storage.debug=e}catch(n){}}function i(){var e;try{e=t.storage.debug}catch(n){}return e}function c(){try{return window.localStorage}catch(e){}}t=e.exports=n(6),t.log=s,t.formatArgs=o,t.save=a,t.load=i,t.useColors=r,t.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:c(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){return JSON.stringify(e)},t.enable(i())},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var o=n(1),s=r(o);t["default"]=s["default"].createClass({displayName:"PlayButton",propTypes:{onClick:s["default"].PropTypes.func},render:function(){return s["default"].createElement("button",{className:"vimeo-play-button",onClick:this.props.onClick,type:"button"},s["default"].createElement("svg",{version:"1.1",viewBox:"0 0 100 100",xmlns:"http://www.w3.org/2000/svg"},s["default"].createElement("path",{d:"M79.674,53.719c2.59-2.046,2.59-5.392,0-7.437L22.566,1.053C19.977-0.993,18,0.035,18,3.335v93.331c0,3.3,1.977,4.326,4.566,2.281L79.674,53.719z"})))}}),e.exports=t["default"]},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var o=n(1),s=r(o);t["default"]=s["default"].createClass({displayName:"Spinner",render:function(){return s["default"].createElement("div",{className:"vimeo-loading"},s["default"].createElement("svg",{height:"32",viewBox:"0 0 32 32",width:"32",xmlns:"http://www.w3.org/2000/svg"},s["default"].createElement("path",{d:"M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4",opacity:".25"}),s["default"].createElement("path",{d:"M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z"})))}}),e.exports=t["default"]},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function o(e){function t(){s(JSON.parse(u.responseText))}function n(){return 4===u.readyState&&200===u.status?s(JSON.parse(u.responseText)):void 0}function r(e){return c("error occured fetching video data",e),a(i)}var o=e.url,s=e.onSuccess,a=e.onError,u=void 0;try{u=new XMLHttpRequest}catch(l){u=new XDomainRequest}return u.onreadystatechange=n,u.onload=t,u.onerror=r,u.open("GET",o,!0),u.send(),u.abort.bind(u)}Object.defineProperty(t,"__esModule",{value:!0}),t.get=o;var s=n(2),a=r(s),i={error:"Sorry, an error occurred on the server"},c=a["default"]("vimeo:ajax")},function(e,t,n){function r(){return t.colors[l++%t.colors.length]}function o(e){function n(){}function o(){var e=o,n=+new Date,s=n-(u||n);e.diff=s,e.prev=u,e.curr=n,u=n,null==e.useColors&&(e.useColors=t.useColors()),null==e.color&&e.useColors&&(e.color=r());var a=Array.prototype.slice.call(arguments);a[0]=t.coerce(a[0]),"string"!=typeof a[0]&&(a=["%o"].concat(a));var i=0;a[0]=a[0].replace(/%([a-z%])/g,function(n,r){if("%%"===n)return n;i++;var o=t.formatters[r];if("function"==typeof o){var s=a[i];n=o.call(e,s),a.splice(i,1),i--}return n}),"function"==typeof t.formatArgs&&(a=t.formatArgs.apply(e,a));var c=o.log||t.log||console.log.bind(console);c.apply(e,a)}n.enabled=!1,o.enabled=!0;var s=t.enabled(e)?o:n;return s.namespace=e,s}function s(e){t.save(e);for(var n=(e||"").split(/[\s,]+/),r=n.length,o=0;r>o;o++)n[o]&&(e=n[o].replace(/\*/g,".*?"),"-"===e[0]?t.skips.push(new RegExp("^"+e.substr(1)+"$")):t.names.push(new RegExp("^"+e+"$")))}function a(){t.enable("")}function i(e){var n,r;for(n=0,r=t.skips.length;r>n;n++)if(t.skips[n].test(e))return!1;for(n=0,r=t.names.length;r>n;n++)if(t.names[n].test(e))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}t=e.exports=o,t.coerce=c,t.disable=a,t.enable=s,t.enabled=i,t.humanize=n(7),t.names=[],t.skips=[],t.formatters={};var u,l=0},function(e,t){function n(e){if(e=""+e,!(e.length>1e4)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var n=parseFloat(t[1]),r=(t[2]||"ms").toLowerCase();switch(r){case"years":case"year":case"yrs":case"yr":case"y":return n*l;case"days":case"day":case"d":return n*u;case"hours":case"hour":case"hrs":case"hr":case"h":return n*c;case"minutes":case"minute":case"mins":case"min":case"m":return n*i;case"seconds":case"second":case"secs":case"sec":case"s":return n*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n}}}}function r(e){return e>=u?Math.round(e/u)+"d":e>=c?Math.round(e/c)+"h":e>=i?Math.round(e/i)+"m":e>=a?Math.round(e/a)+"s":e+"ms"}function o(e){return s(e,u,"day")||s(e,c,"hour")||s(e,i,"minute")||s(e,a,"second")||e+" ms"}function s(e,t,n){return t>e?void 0:1.5*t>e?Math.floor(e/t)+" "+n:Math.ceil(e/t)+" "+n+"s"}var a=1e3,i=60*a,c=60*i,u=24*c,l=365.25*u;e.exports=function(e,t){return t=t||{},"string"==typeof e?n(e):t["long"]?o(e):r(e)}},function(e,t){"use strict";var n=function(e){var t,n={};if(!(e instanceof Object)||Array.isArray(e))throw new Error("keyMirror(...): Argument must be an object.");for(t in e)e.hasOwnProperty(t)&&(n[t]=t);return n};e.exports=n}])});
\ No newline at end of file
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.ReactVimeo=t(require("react")):e.ReactVimeo=t(e.React)}(this,function(e){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function o(e){return e.charAt(0).toUpperCase()+e.substring(1)}function s(e,t){return t["on"+o(e)]||function(){}}function a(e,t,n,r){try{n.contentWindow.postMessage({method:e,value:t},r)}catch(o){return o}return null}Object.defineProperty(t,"__esModule",{value:!0});var i=n(1),c=r(i),u=n(11),l=r(u),d=n(7),f=r(d),p=n(4),m=r(p),h=n(2),g=r(h),y=n(3),v=r(y),w=m["default"]("vimeo:player"),b=function(){},x=l["default"]({cuechange:null,finish:null,loadProgress:null,pause:null,play:null,playProgress:null,seek:null});t["default"]=c["default"].createClass({displayName:"Vimeo",propTypes:{className:i.PropTypes.string,loading:i.PropTypes.element,onCuechange:i.PropTypes.func,onError:i.PropTypes.func,onFinish:i.PropTypes.func,onLoadProgress:i.PropTypes.func,onPause:i.PropTypes.func,onPlay:i.PropTypes.func,onPlayProgress:i.PropTypes.func,onReady:i.PropTypes.func,onSeek:i.PropTypes.func,playButton:i.PropTypes.node,videoId:i.PropTypes.string.isRequired},getDefaultProps:function(){var e=Object.keys(x).concat(["ready"]).reduce(function(e,t){return e["on"+o(t)]=b,e},{});return e.className="vimeo",e},getInitialState:function(){return{imageLoaded:!1,playerOrigin:"*",showingVideo:!1,thumb:null}},componentWillReceiveProps:function(e){e.videoId!==this.props.videoId&&this.setState({thumb:null,imageLoaded:!1,showingVideo:!1})},componentDidMount:function(){this.fetchVimeoData()},componentDidUpdate:function(){this.fetchVimeoData()},componentWillUnmount:function(){var e="undefined"!=typeof window?window.removeEventListener.bind(window):b;e("message",this.onMessage)},addMessageListener:function(){var e="undefined"!=typeof window?window.addEventListener.bind(window):b;e("message",this.onMessage)},onError:function(e){throw this.props.onError&&this.props.onError(e),e},onMessage:function(e){var t=this.props.onReady,n=this.state.playerOrigin;if("*"===n&&this.setState({playerOrigin:e.origin}),!/^https?:\/\/player.vimeo.com/.test(e.origin))return!1;var r=void 0;try{r=JSON.parse(e.data)}catch(o){w("error parsing message",o),r={}}if("ready"===r.event){var a=this.refs.player;return w("player ready"),this.onReady(a,"*"===n?e.origin:n),t(r)}s(r.event,this.props)(r)},onReady:function(e,t){var n=this;Object.keys(x).forEach(function(r){var o=a("addEventListener",r,e,t);o&&n.onError(o)})},playVideo:function(e){e.preventDefault(),this.setState({showingVideo:!0})},getIframeUrl:function(){return"//player.vimeo.com/video/"+this.props.videoId+"?autoplay=1"},fetchVimeoData:function(){var e=this;if(!this.state.imageLoaded){var t=this.props.videoId;f["default"]("//vimeo.com/api/v2/video/"+t+".json",{prefix:"vimeo"},function(t,n){t&&(w("jsonp err: ",t.message),e.onError(t)),w("jsonp response",n),e.setState({thumb:n[0].thumbnail_large,imageLoaded:!0})})}},renderImage:function(){if(!this.state.showingVideo&&this.state.imageLoaded){var e={backgroundImage:"url("+this.state.thumb+")",display:this.state.showingVideo?"none":"block",height:"100%",width:"100%"};return c["default"].createElement("div",{className:"vimeo-image",style:e},c["default"].createElement(g["default"],{onClick:this.playVideo}))}},renderIframe:function(){if(this.state.showingVideo){this.addMessageListener();var e={display:this.state.showingVideo?"block":"none",height:"100%",width:"100%"};return c["default"].createElement("div",{className:"vimeo-embed",style:e},c["default"].createElement("iframe",{frameBorder:"0",ref:"player",src:this.getIframeUrl()}))}},renderLoading:function(e,t){return e?void 0:t?t:c["default"].createElement(v["default"],null)},render:function(){return c["default"].createElement("div",{className:this.props.className},this.renderLoading(this.state.imageLoaded,this.props.loading),this.renderImage(),this.renderIframe())}}),e.exports=t["default"]},function(t,n){t.exports=e},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var o=n(1),s=r(o);t["default"]=s["default"].createClass({displayName:"PlayButton",propTypes:{onClick:s["default"].PropTypes.func},render:function(){return s["default"].createElement("button",{className:"vimeo-play-button",onClick:this.props.onClick,type:"button"},s["default"].createElement("svg",{version:"1.1",viewBox:"0 0 100 100",xmlns:"http://www.w3.org/2000/svg"},s["default"].createElement("path",{d:"M79.674,53.719c2.59-2.046,2.59-5.392,0-7.437L22.566,1.053C19.977-0.993,18,0.035,18,3.335v93.331c0,3.3,1.977,4.326,4.566,2.281L79.674,53.719z"})))}}),e.exports=t["default"]},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var o=n(1),s=r(o);t["default"]=s["default"].createClass({displayName:"Spinner",render:function(){return s["default"].createElement("div",{className:"vimeo-loading"},s["default"].createElement("svg",{height:"32",viewBox:"0 0 32 32",width:"32",xmlns:"http://www.w3.org/2000/svg"},s["default"].createElement("path",{d:"M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4",opacity:".25"}),s["default"].createElement("path",{d:"M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z"})))}}),e.exports=t["default"]},function(e,t,n){function r(){return"WebkitAppearance"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31}function o(){var e=arguments,n=this.useColors;if(e[0]=(n?"%c":"")+this.namespace+(n?" %c":" ")+e[0]+(n?"%c ":" ")+"+"+t.humanize(this.diff),!n)return e;var r="color: "+this.color;e=[e[0],r,"color: inherit"].concat(Array.prototype.slice.call(e,1));var o=0,s=0;return e[0].replace(/%[a-z%]/g,function(e){"%%"!==e&&(o++,"%c"===e&&(s=o))}),e.splice(s,0,r),e}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?t.storage.removeItem("debug"):t.storage.debug=e}catch(n){}}function i(){var e;try{e=t.storage.debug}catch(n){}return e}function c(){try{return window.localStorage}catch(e){}}t=e.exports=n(5),t.log=s,t.formatArgs=o,t.save=a,t.load=i,t.useColors=r,t.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:c(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){return JSON.stringify(e)},t.enable(i())},function(e,t,n){function r(){return t.colors[l++%t.colors.length]}function o(e){function n(){}function o(){var e=o,n=+new Date,s=n-(u||n);e.diff=s,e.prev=u,e.curr=n,u=n,null==e.useColors&&(e.useColors=t.useColors()),null==e.color&&e.useColors&&(e.color=r());var a=Array.prototype.slice.call(arguments);a[0]=t.coerce(a[0]),"string"!=typeof a[0]&&(a=["%o"].concat(a));var i=0;a[0]=a[0].replace(/%([a-z%])/g,function(n,r){if("%%"===n)return n;i++;var o=t.formatters[r];if("function"==typeof o){var s=a[i];n=o.call(e,s),a.splice(i,1),i--}return n}),"function"==typeof t.formatArgs&&(a=t.formatArgs.apply(e,a));var c=o.log||t.log||console.log.bind(console);c.apply(e,a)}n.enabled=!1,o.enabled=!0;var s=t.enabled(e)?o:n;return s.namespace=e,s}function s(e){t.save(e);for(var n=(e||"").split(/[\s,]+/),r=n.length,o=0;r>o;o++)n[o]&&(e=n[o].replace(/\*/g,".*?"),"-"===e[0]?t.skips.push(new RegExp("^"+e.substr(1)+"$")):t.names.push(new RegExp("^"+e+"$")))}function a(){t.enable("")}function i(e){var n,r;for(n=0,r=t.skips.length;r>n;n++)if(t.skips[n].test(e))return!1;for(n=0,r=t.names.length;r>n;n++)if(t.names[n].test(e))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}t=e.exports=o,t.coerce=c,t.disable=a,t.enable=s,t.enabled=i,t.humanize=n(6),t.names=[],t.skips=[],t.formatters={};var u,l=0},function(e,t){function n(e){if(e=""+e,!(e.length>1e4)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var n=parseFloat(t[1]),r=(t[2]||"ms").toLowerCase();switch(r){case"years":case"year":case"yrs":case"yr":case"y":return n*l;case"days":case"day":case"d":return n*u;case"hours":case"hour":case"hrs":case"hr":case"h":return n*c;case"minutes":case"minute":case"mins":case"min":case"m":return n*i;case"seconds":case"second":case"secs":case"sec":case"s":return n*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n}}}}function r(e){return e>=u?Math.round(e/u)+"d":e>=c?Math.round(e/c)+"h":e>=i?Math.round(e/i)+"m":e>=a?Math.round(e/a)+"s":e+"ms"}function o(e){return s(e,u,"day")||s(e,c,"hour")||s(e,i,"minute")||s(e,a,"second")||e+" ms"}function s(e,t,n){return t>e?void 0:1.5*t>e?Math.floor(e/t)+" "+n:Math.ceil(e/t)+" "+n+"s"}var a=1e3,i=60*a,c=60*i,u=24*c,l=365.25*u;e.exports=function(e,t){return t=t||{},"string"==typeof e?n(e):t["long"]?o(e):r(e)}},function(e,t,n){function r(){}function o(e,t,n){function o(){c.parentNode&&c.parentNode.removeChild(c),window[d]=r,u&&clearTimeout(u)}function i(){window[d]&&o()}"function"==typeof t&&(n=t,t={}),t||(t={});var c,u,l=t.prefix||"__jp",d=t.name||l+a++,f=t.param||"callback",p=null!=t.timeout?t.timeout:6e4,m=encodeURIComponent,h=document.getElementsByTagName("script")[0]||document.head;return p&&(u=setTimeout(function(){o(),n&&n(new Error("Timeout"))},p)),window[d]=function(e){s("jsonp got",e),o(),n&&n(null,e)},e+=(~e.indexOf("?")?"&":"?")+f+"="+m(d),e=e.replace("?&","?"),s('jsonp req "%s"',e),c=document.createElement("script"),c.src=e,h.parentNode.insertBefore(c,h),i}var s=n(8)("jsonp");e.exports=o;var a=0},function(e,t,n){function r(){return"WebkitAppearance"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31}function o(){var e=arguments,n=this.useColors;if(e[0]=(n?"%c":"")+this.namespace+(n?" %c":" ")+e[0]+(n?"%c ":" ")+"+"+t.humanize(this.diff),!n)return e;var r="color: "+this.color;e=[e[0],r,"color: inherit"].concat(Array.prototype.slice.call(e,1));var o=0,s=0;return e[0].replace(/%[a-z%]/g,function(e){"%%"!==e&&(o++,"%c"===e&&(s=o))}),e.splice(s,0,r),e}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?u.removeItem("debug"):u.debug=e}catch(t){}}function i(){var e;try{e=u.debug}catch(t){}return e}function c(){try{return window.localStorage}catch(e){}}t=e.exports=n(9),t.log=s,t.formatArgs=o,t.save=a,t.load=i,t.useColors=r;var u;u="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:c(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){return JSON.stringify(e)},t.enable(i())},function(e,t,n){function r(){return t.colors[l++%t.colors.length]}function o(e){function n(){}function o(){var e=o,n=+new Date,s=n-(u||n);e.diff=s,e.prev=u,e.curr=n,u=n,null==e.useColors&&(e.useColors=t.useColors()),null==e.color&&e.useColors&&(e.color=r());var a=Array.prototype.slice.call(arguments);a[0]=t.coerce(a[0]),"string"!=typeof a[0]&&(a=["%o"].concat(a));var i=0;a[0]=a[0].replace(/%([a-z%])/g,function(n,r){if("%%"===n)return n;i++;var o=t.formatters[r];if("function"==typeof o){var s=a[i];n=o.call(e,s),a.splice(i,1),i--}return n}),"function"==typeof t.formatArgs&&(a=t.formatArgs.apply(e,a));var c=o.log||t.log||console.log.bind(console);c.apply(e,a)}n.enabled=!1,o.enabled=!0;var s=t.enabled(e)?o:n;return s.namespace=e,s}function s(e){t.save(e);for(var n=(e||"").split(/[\s,]+/),r=n.length,o=0;r>o;o++)n[o]&&(e=n[o].replace(/\*/g,".*?"),"-"===e[0]?t.skips.push(new RegExp("^"+e.substr(1)+"$")):t.names.push(new RegExp("^"+e+"$")))}function a(){t.enable("")}function i(e){var n,r;for(n=0,r=t.skips.length;r>n;n++)if(t.skips[n].test(e))return!1;for(n=0,r=t.names.length;r>n;n++)if(t.names[n].test(e))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}t=e.exports=o,t.coerce=c,t.disable=a,t.enable=s,t.enabled=i,t.humanize=n(10),t.names=[],t.skips=[],t.formatters={};var u,l=0},function(e,t){function n(e){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var n=parseFloat(t[1]),r=(t[2]||"ms").toLowerCase();switch(r){case"years":case"year":case"yrs":case"yr":case"y":return n*l;case"days":case"day":case"d":return n*u;case"hours":case"hour":case"hrs":case"hr":case"h":return n*c;case"minutes":case"minute":case"mins":case"min":case"m":return n*i;case"seconds":case"second":case"secs":case"sec":case"s":return n*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n}}}function r(e){return e>=u?Math.round(e/u)+"d":e>=c?Math.round(e/c)+"h":e>=i?Math.round(e/i)+"m":e>=a?Math.round(e/a)+"s":e+"ms"}function o(e){return s(e,u,"day")||s(e,c,"hour")||s(e,i,"minute")||s(e,a,"second")||e+" ms"}function s(e,t,n){return t>e?void 0:1.5*t>e?Math.floor(e/t)+" "+n:Math.ceil(e/t)+" "+n+"s"}var a=1e3,i=60*a,c=60*i,u=24*c,l=365.25*u;e.exports=function(e,t){return t=t||{},"string"==typeof e?n(e):t["long"]?o(e):r(e)}},function(e,t){"use strict";var n=function(e){var t,n={};if(!(e instanceof Object)||Array.isArray(e))throw new Error("keyMirror(...): Argument must be an object.");for(t in e)e.hasOwnProperty(t)&&(n[t]=t);return n};e.exports=n}])});
\ No newline at end of file
diff --git a/package.json b/package.json
index d4b0945..92940ba 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "react-vimeo",
-  "version": "0.0.3",
+  "version": "0.1.0",
   "description": "React component to load video from Vimeo",
   "author": {
     "name": "Berkeley Martinez",
@@ -37,7 +37,7 @@
     "test": "npm run lint"
   },
   "peerDependencies": {
-    "react": ">=0.13.0"
+    "react": ">=0.14.0"
   },
   "devDependencies": {
     "babel-core": "^5.6.15",
@@ -50,12 +50,15 @@
     "lodash": "^2.4.1",
     "nib": "^1.1.0",
     "node-libs-browser": "^0.5.2",
+    "react": "^0.14.6",
+    "react-dom": "^0.14.6",
     "stylus": "^0.51.1",
     "webpack": "^1.10.1",
     "yargs": "^1.3.2"
   },
   "dependencies": {
     "debug": "^2.2.0",
+    "jsonp": "^0.2.0",
     "keymirror": "^0.1.1"
   }
 }
diff --git a/src/Vimeo.jsx b/src/Vimeo.jsx
index 8e9c25a..cf4b43d 100644
--- a/src/Vimeo.jsx
+++ b/src/Vimeo.jsx
@@ -1,12 +1,11 @@
 import React, { PropTypes } from 'react';
 import keyMirror from 'keymirror';
+import jsonp from 'jsonp';
 import debugFactory from 'debug';
 
 import PlayButton from './Play-Button';
 import Spinner from './Spinner';
 
-import { get } from './ajax';
-
 const debug = debugFactory('vimeo:player');
 const noop = () => {};
 const playerEvents = keyMirror({
@@ -24,12 +23,16 @@ function capitalize(str) {
 }
 
 function getFuncForEvent(event, props) {
-  return props['on' + capitalize(event)];
+  return props['on' + capitalize(event)] || (() => {});
 }
 
 function post(method, value, player, playerOrigin) {
-  player.contentWindow.postMessage({ method, value }, playerOrigin);
-  return player;
+  try {
+    player.contentWindow.postMessage({ method, value }, playerOrigin);
+  } catch (err) {
+    return err;
+  }
+  return null;
 }
 
 export default React.createClass({
@@ -106,6 +109,13 @@ export default React.createClass({
     addEventListener('message', this.onMessage);
   },
 
+  onError(err) {
+    if (this.props.onError) {
+      this.props.onError(err);
+    }
+    throw err;
+  },
+
   onMessage(e) {
     const { onReady } = this.props;
     const { playerOrigin } = this.state;
@@ -121,10 +131,16 @@ export default React.createClass({
       return false;
     }
 
-    const dats = JSON.parse(e.data);
+    let dats;
+    try {
+      dats = JSON.parse(e.data);
+    } catch (err) {
+      debug('error parsing message' , err);
+      dats = {};
+    }
 
     if (dats.event === 'ready') {
-      const player = React.findDOMNode(this.refs.player);
+      const { player } = this.refs;
       debug('player ready');
       this.onReady(
         player,
@@ -133,16 +149,15 @@ export default React.createClass({
       return onReady(dats);
     }
 
-    const potentialFunc = getFuncForEvent(dats.event, this.props);
-
-    if (typeof potentialFunc === 'function') {
-      potentialFunc(dats);
-    }
+    getFuncForEvent(dats.event, this.props)(dats);
   },
 
   onReady(player, playerOrigin) {
     Object.keys(playerEvents).forEach(event => {
-      post('addEventListener', event, player, playerOrigin);
+      var err = post('addEventListener', event, player, playerOrigin);
+      if (err) {
+        this.onError(err);
+      }
     });
   },
 
@@ -161,17 +176,23 @@ export default React.createClass({
     }
     const id = this.props.videoId;
 
-    get({
-      url: `//vimeo.com/api/v2/video/${id}.json`,
-      onSuccess: (res) => {
-        debug('ajax response', res);
+    jsonp(
+      `//vimeo.com/api/v2/video/${id}.json`,
+      {
+        prefix: 'vimeo'
+      },
+      (err, res) => {
+        if (err) {
+          debug('jsonp err: ', err.message);
+          this.onError(err);
+        }
+        debug('jsonp response', res);
         this.setState({
           thumb: res[0].thumbnail_large,
           imageLoaded: true
         });
-      },
-      onError: this.props.onError || (() => {})
-    });
+      }
+    );
   },
 
   renderImage() {
diff --git a/src/ajax.js b/src/ajax.js
deleted file mode 100644
index d5771bb..0000000
--- a/src/ajax.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import debugFactory from 'debug';
-
-const errMessage = { error: 'Sorry, an error occurred on the server' };
-const debug = debugFactory('vimeo:ajax');
-
-export function get(opts) {
-  const url = opts.url;
-  const onSuccess = opts.onSuccess;
-  const onError = opts.onError;
-  let req;
-
-  try {
-    req = new XMLHttpRequest();
-  } catch (e) {
-    req = new XDomainRequest();
-  }
-
-  // XDomainRequest onload
-  // ie 8-9 support
-  function oldIE() {
-    onSuccess(JSON.parse(req.responseText));
-  }
-
-  // XMLHttpRequest onload
-  function onReadyStateChange() {
-    if (req.readyState !== 4 || req.status !== 200) { return; }
-    return onSuccess(JSON.parse(req.responseText));
-  }
-
-  function errHandler(err) {
-    debug('error occured fetching video data', err);
-    return onError(errMessage);
-  }
-
-  req.onreadystatechange = onReadyStateChange;
-  req.onload = oldIE;
-  req.onerror = errHandler;
-  req.open('GET', url, true);
-  req.send();
-
-  return req.abort.bind(req);
-}
