diff --git a/camo-image-proxy.php b/camo-image-proxy.php
index 53060188cd52fc5add5a1c020326a950d2045db6..f431994b30eb847c9e06ae4a0002a376ff7dc44d 100755
--- a/camo-image-proxy.php
+++ b/camo-image-proxy.php
@@ -29,11 +29,21 @@ require_once PLUGIN_PATH . '/inc/class-options.php';
 /**
  * Options page
  */
-if ( is_admin() ) {
-	require_once PLUGIN_PATH . '/inc/class-options-page.php';
-}
+require_once PLUGIN_PATH . '/inc/class-options-page.php';
 
 /**
  * Assorted functions
  */
 require_once PLUGIN_PATH . '/inc/functions.php';
+
+/**
+ * Load plugin singletons
+ */
+function init() {
+	Options::instance();
+
+	if ( is_admin() ) {
+		Options_Page::instance();
+	}
+}
+add_action( 'init', __NAMESPACE__ . '\init' );
diff --git a/inc/class-options-page.php b/inc/class-options-page.php
index 7fbb5260f6b689218a799117b3ccf4a8d3c87907..0ed5cdb41bf85cbf0249e00b166abcd095d37835 100644
--- a/inc/class-options-page.php
+++ b/inc/class-options-page.php
@@ -13,10 +13,36 @@ namespace Camo_Image_Proxy;
 class Options_Page {
 	use Singleton;
 
+	/**
+	 * Settings screen section
+	 *
+	 * @var string
+	 */
+	private $section = 'camp-image-proxy';
+
+	/**
+	 * Field labels
+	 *
+	 * @var array
+	 */
+	private $labels = [];
+
+	/**
+	 * Option name
+	 *
+	 * @var string
+	 */
+	private $name;
+
 	/**
 	 * Hooks
 	 */
 	public function setup() {
+		$this->name = Options::instance()->name;
+
+		$this->labels['host'] = __( 'Host', 'camo-image-proxy' );
+		$this->labels['key']  = __( 'Shared Key', 'camo-image-proxy' );
+
 		add_action( 'admin_init', [ $this, 'action_admin_init' ] );
 	}
 
@@ -24,9 +50,37 @@ class Options_Page {
 	 * Add fields to Media settings page
 	 */
 	public function action_admin_init() {
-		//register_setting();
+		register_setting( 'media', $this->name, [ Options::instance(), 'sanitize_all' ] );
+		add_settings_section( $this->section, __( 'Camo Image Proxy', 'camo-image-proxy' ), '__return_false', 'media' );
+
+		foreach ( $this->labels as $key => $label ) {
+			$args = [
+				'option' => $key,
+				'label'  => $label,
+			];
+			add_settings_field( $key, $label, [ $this, 'screen' ], 'media', $this->section, $args );
+		}
+	}
+
+	/**
+	 * Render options field
+	 *
+	 * @param array $args Field arguments.
+	 */
+	public function screen( $args ) {
+		$value      = Options::instance()->get( $args['option'] );
+		$input_type = 'host' === $args['option'] ? 'url' : 'text';
+		$name       = sprintf( '%1$s[%2$s]', $this->name, $args['option'] );
+		$html_id    = sprintf( '%1$s-%2$s', str_replace( '_', '-', $this->name ), $args['option'] );
 
-		//add_settings_section();
-		//add_settings_field();
+		?>
+		<input
+			type="<?php echo esc_attr( $input_type ); ?>"
+			name="<?php echo esc_html( $name ); ?>"
+			class="regular-text"
+			id="<?php echo esc_attr( $html_id ); ?>"
+			value="<?php echo esc_attr( $value ); ?>"
+		/>
+		<?php
 	}
 }
diff --git a/inc/class-options.php b/inc/class-options.php
index 67ff87b0dea184b1ab7438732018a9439fbc0b6b..b2addfdb034b2b028029951e3bd989f0ba85f4b2 100644
--- a/inc/class-options.php
+++ b/inc/class-options.php
@@ -80,6 +80,21 @@ class Options {
 	 * @return bool
 	 */
 	public function set( string $option, $value ) : bool {
+		$value              = $this->sanitize( $option, $value );
+		$options            = $this->get_all();
+		$options[ $option ] = $value;
+
+		return update_option( $this->name, $options );
+	}
+
+	/**
+	 * Sanitize option
+	 *
+	 * @param string $option Plugin option.
+	 * @param mixed  $value Option value to sanitize.
+	 * @return mixed
+	 */
+	public function sanitize( string $option, $value ) {
 		switch ( $option ) {
 			case 'host':
 				$value = esc_url( $value );
@@ -93,9 +108,20 @@ class Options {
 				return false;
 		}
 
-		$options            = $this->get_all();
-		$options[ $option ] = $value;
+		return $value;
+	}
 
-		return update_option( $this->name, $options );
+	/**
+	 * Sanitize array of options
+	 *
+	 * @param array $options Options to sanitize.
+	 * @return array
+	 */
+	public function sanitize_all( array $options ) : array {
+		foreach ( $options as $option => $value ) {
+			$options[ $option ] = $this->sanitize( $option, $value );
+		}
+
+		return $options;
 	}
 }
diff --git a/inc/functions.php b/inc/functions.php
index 7666210550e2455d5e4c01e6b60553f45ddc0699..6179babfeff42a399f88114852510367ed34a8ac 100644
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -12,6 +12,6 @@ namespace Camo_Image_Proxy;
  *
  * @return object
  */
-function options() {
+function Options() {
 	return Options::instance();
 }