diff --git a/android/app/build.gradle b/android/app/build.gradle
index 1084da92383b60929c2d2fad7db1ef1559371998..fa56b475b947fe38815dcf124054886df40ae966 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -139,6 +139,8 @@ android {
 
 dependencies {
     compile project(':react-native-vector-icons')
+    compile project(':react-native-fs')
+    compile project(':react-native-document-picker')
     compile project(':react-native-share')
     compile project(':realm')
     compile fileTree(dir: "libs", include: ["*.jar"])
diff --git a/android/app/src/main/java/com/drip/MainApplication.java b/android/app/src/main/java/com/drip/MainApplication.java
index 44756abd812f72286b8f54b1a044468f8899ef4d..4dc63a4e890ef14381f722b9a044c3114945f809 100644
--- a/android/app/src/main/java/com/drip/MainApplication.java
+++ b/android/app/src/main/java/com/drip/MainApplication.java
@@ -4,6 +4,8 @@ import android.app.Application;
 
 import com.facebook.react.ReactApplication;
 import com.oblador.vectoricons.VectorIconsPackage;
+import com.rnfs.RNFSPackage;
+import com.reactnativedocumentpicker.ReactNativeDocumentPicker;
 import cl.json.RNSharePackage;
 import cl.json.ShareApplication;
 import io.realm.react.RealmReactPackage;
@@ -28,6 +30,8 @@ public class MainApplication extends Application implements ReactApplication, Sh
       return Arrays.<ReactPackage>asList(
           new MainReactPackage(),
             new VectorIconsPackage(),
+            new RNFSPackage(),
+            new ReactNativeDocumentPicker(),
             new RNSharePackage(),
             new RealmReactPackage()
       );
diff --git a/android/settings.gradle b/android/settings.gradle
index 4e17216719a3e145126ce7913aba6a4b8acefe3c..6a9c8c84200f3d0b63b9697454df468f2d5e1484 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -1,6 +1,10 @@
 rootProject.name = 'drip'
 include ':react-native-vector-icons'
 project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
+include ':react-native-fs'
+project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android')
+include ':react-native-document-picker'
+project(':react-native-document-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-document-picker/android')
 include ':react-native-share'
 project(':react-native-share').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-share/android')
 include ':realm'
diff --git a/components/cycle-day/cycle-day-overview.js b/components/cycle-day/cycle-day-overview.js
index f92934b54305277f47588f56b4087ad296573db2..b127b7471fe1742792f6f1e3bf9b8bd781799515 100644
--- a/components/cycle-day/cycle-day-overview.js
+++ b/components/cycle-day/cycle-day-overview.js
@@ -98,11 +98,20 @@ export default class DayView extends Component {
           <Text style={styles.symptomDayView}>Desire</Text>
           <View style={styles.symptomEditButton}>
             <Button
-              onPress={() => this.showView('desireEditView')}
+              onPress={() => this.showView('DesireEditView')}
               title={getLabel('desire', cycleDay.desire)}>
             </Button>
           </View>
         </View>
+        <View style={styles.symptomViewRowInline}>
+          <Text style={styles.symptomDayView}>Sex</Text>
+          <View style={styles.symptomEditButton}>
+            <Button
+              onPress={() => this.showView('SexEditView')}
+              title={getLabel('sex', cycleDay.sex)}>
+            </Button>
+          </View>
+        </View>
       </View >
     )
   }
@@ -132,15 +141,22 @@ function getLabel(symptomName, symptom) {
         typeof mucus.texture === 'number' &&
         typeof mucus.value === 'number'
       ) {
-        let mucusLabel = `${feelingLabels[mucus.feeling]} + ${textureLabels[mucus.texture]} ( ${computeSensiplanMucusLabels[mucus.value]} )`
+        let mucusLabel =
+          `${feelingLabels[mucus.feeling]} +
+          ${textureLabels[mucus.texture]}
+          ( ${computeSensiplanMucusLabels[mucus.value]} )`
         if (mucus.exclude) mucusLabel = "( " + mucusLabel + " )"
         return mucusLabel
       }
     },
     cervix: cervix => {
       if (cervix.opening > -1 && cervix.firmness > -1) {
-        let cervixLabel = `${openingLabels[cervix.opening]} + ${firmnessLabels[cervix.firmness]}`
-        if (cervix.position > -1) cervixLabel += `+ ${positionLabels[cervix.position]}`
+        let cervixLabel =
+          `${openingLabels[cervix.opening]} +
+          ${firmnessLabels[cervix.firmness]}`
+        if (cervix.position > -1) {
+          cervixLabel += `+ ${positionLabels[cervix.position]}`
+        }
         if (cervix.exclude) cervixLabel = "( " + cervixLabel + " )"
         return cervixLabel
       }
@@ -153,6 +169,17 @@ function getLabel(symptomName, symptom) {
         const desireLabel = `${intensityLabels[desire.value]}`
         return desireLabel
       }
+    },
+    sex: sex => {
+      let sexLabel = ''
+      if ( sex.solo || sex.partner ) {
+        sexLabel += 'Activity '
+      }
+      if (sex.condom || sex.pill || sex.iud ||
+        sex.patch || sex.ring || sex.implant || sex.other) {
+        sexLabel += 'Contraceptive'
+      }
+      return sexLabel ? sexLabel : 'edit'
     }
   }
 
diff --git a/components/cycle-day/labels/labels.js b/components/cycle-day/labels/labels.js
index 68735ee1305ea3cdfc2001311c716d67835a172f..ee88428f9eae95670ebf853af6ebafc85b4d33c7 100644
--- a/components/cycle-day/labels/labels.js
+++ b/components/cycle-day/labels/labels.js
@@ -6,6 +6,19 @@ export const cervixOpening = ['closed', 'medium', 'open']
 export const cervixFirmness = ['hard', 'soft']
 export const cervixPosition = ['low', 'medium', 'high']
 export const intensity = ['low', 'medium', 'high']
+export const sexActivity = {
+  solo: 'Solo',
+  partner: 'Partner'
+}
+export const contraceptives = {
+  condom: 'Condom',
+  pill: 'Pill',
+  iud: 'IUD',
+  patch: 'Patch',
+  ring: 'Ring',
+  implant: 'Implant',
+  other: 'Other'
+}
 
 export const fertilityStatus = {
   fertile: 'fertile',
diff --git a/components/cycle-day/symptoms/index.js b/components/cycle-day/symptoms/index.js
index 617dbab46d2d1d59b522ddc17712a98271c1ed25..c3583df86348327d9dd3bdaa1d83975926d3694b 100644
--- a/components/cycle-day/symptoms/index.js
+++ b/components/cycle-day/symptoms/index.js
@@ -4,6 +4,7 @@ import MucusEditView from './mucus'
 import CervixEditView from './cervix'
 import NoteEditView from './note'
 import DesireEditView from './desire'
+import SexEditView from './sex'
 
 export default {
   BleedingEditView,
@@ -11,5 +12,6 @@ export default {
   MucusEditView,
   CervixEditView,
   NoteEditView,
-  DesireEditView
-}
\ No newline at end of file
+  DesireEditView,
+  SexEditView
+}
diff --git a/components/cycle-day/symptoms/sex.js b/components/cycle-day/symptoms/sex.js
new file mode 100644
index 0000000000000000000000000000000000000000..d9ec3366402edab57e054a993363cecca41d6ab0
--- /dev/null
+++ b/components/cycle-day/symptoms/sex.js
@@ -0,0 +1,156 @@
+import React, { Component } from 'react'
+import {
+  CheckBox,
+  Text,
+  TextInput,
+  View
+} from 'react-native'
+import styles from '../../../styles'
+import { saveSymptom } from '../../../db'
+import {
+  sexActivity as activityLabels,
+  contraceptives as contraceptiveLabels
+} from '../labels/labels'
+
+export default class Sex extends Component {
+  constructor(props) {
+    super(props)
+    this.cycleDay = props.cycleDay
+    this.state = {}
+    if (this.cycleDay.sex !== null ) {
+      Object.assign(this.state, this.cycleDay.sex)
+      // We make sure other is always true when there is a note,
+      // e.g. when import is messed up.
+      if (this.cycleDay.sex && this.cycleDay.sex.note) {
+        this.state.other = true
+      }
+    }
+  }
+
+  render() {
+
+    return (
+      <View style={styles.symptomEditView}>
+        <Text style={styles.symptomDayView}>SEX</Text>
+        <View style={styles.symptomViewRowInline}>
+          <Text style={styles.symptomDayView}>{activityLabels.solo}</Text>
+          <CheckBox
+            value={this.state.solo}
+            onValueChange={(val) => {
+              this.setState({solo: val})
+            }}
+          />
+          <Text style={styles.symptomDayView}>{activityLabels.partner}</Text>
+          <CheckBox
+            value={this.state.partner}
+            onValueChange={(val) => {
+              this.setState({partner: val})
+            }}
+          />
+        </View>
+        <Text style={styles.symptomDayView}>CONTRACEPTIVES</Text>
+        <View style={styles.symptomViewRowInline}>
+          <Text style={styles.symptomDayView}>
+            {contraceptiveLabels.condom}
+          </Text>
+          <CheckBox
+            value={this.state.condom}
+            onValueChange={(val) => {
+              this.setState({condom: val})
+            }}
+          />
+          <Text style={styles.symptomDayView}>
+            {contraceptiveLabels.pill}
+          </Text>
+          <CheckBox
+            value={this.state.pill}
+            onValueChange={(val) => {
+              this.setState({pill: val})
+            }}
+          />
+        </View>
+        <View style={styles.symptomViewRowInline}>
+          <Text style={styles.symptomDayView}>
+            {contraceptiveLabels.iud}
+          </Text>
+          <CheckBox
+            value={this.state.iud}
+            onValueChange={(val) => {
+              this.setState({iud: val})
+            }}
+          />
+          <Text style={styles.symptomDayView}>
+            {contraceptiveLabels.patch}
+          </Text>
+          <CheckBox
+            value={this.state.patch}
+            onValueChange={(val) => {
+              this.setState({patch: val})
+            }}
+          />
+        </View>
+        <View style={styles.symptomViewRowInline}>
+          <Text style={styles.symptomDayView}>
+            {contraceptiveLabels.ring}
+          </Text>
+          <CheckBox
+            value={this.state.ring}
+            onValueChange={(val) => {
+              this.setState({ring: val})
+            }}
+          />
+          <Text style={styles.symptomDayView}>
+            {contraceptiveLabels.implant}
+          </Text>
+          <CheckBox
+            value={this.state.implant}
+            onValueChange={(val) => {
+              this.setState({implant: val})
+            }}
+          />
+        </View>
+        <View style={styles.symptomViewRowInline}>
+          <Text style={styles.symptomDayView}>
+            {contraceptiveLabels.other}
+          </Text>
+          <CheckBox
+            value={this.state.other}
+            onValueChange={(val) => {
+              this.setState({
+                other: val,
+                focusTextArea: true
+              })
+            }}
+          />
+        </View>
+        { this.state.other &&
+          <TextInput
+            autoFocus={this.state.focusTextArea}
+            multiline={true}
+            placeholder="Enter"
+            value={this.state.note}
+            onChangeText={(val) => {
+              this.setState({note: val})
+            }}
+          />
+        }
+        <View style={styles.actionButtonRow}>
+          {this.props.makeActionButtons(
+            {
+              symptom: 'sex',
+              cycleDay: this.cycleDay,
+              saveAction: () => {
+                const copyOfState = Object.assign({}, this.state)
+                if (!copyOfState.other) {
+                  copyOfState.note = null
+                }
+                saveSymptom('sex', this.cycleDay, copyOfState)
+              },
+              saveDisabled: Object.values(this.state).every(value => !value)
+            }
+          )}
+        </View>
+      </View>
+    )
+  }
+}
diff --git a/components/labels.js b/components/labels.js
index cd361c8499803cd2d6cd83d1d961a710891646c7..99400a2de63b6480c53cc5175b4fd1c24884bc59 100644
--- a/components/labels.js
+++ b/components/labels.js
@@ -1,10 +1,33 @@
 export const settings = {
-  errors: {
-    noData: 'There is no data to export',
-    couldNotConvert: 'Could not convert data to CSV',
-    problemSharing: 'There was a problem sharing the data export file'
+  shared: {
+    cancel: 'Cancel',
+    errorTitle: 'Error',
+    successTitle: 'Success'
   },
-  exportTitle: 'My Drip data export',
-  exportSubject: 'My Drip data export',
-  buttonLabel: 'Export data'
+  export: {
+    errors: {
+      noData: 'There is no data to export',
+      couldNotConvert: 'Could not convert data to CSV',
+      problemSharing: 'There was a problem sharing the data export file'
+    },
+    title: 'My Drip data export',
+    subject: 'My Drip data export',
+    button: 'Export data',
+  },
+  import: {
+    button: 'Import data',
+    title: 'Keep existing data?',
+    message: `There are two options for the import:
+1. Keep existing cycle days and replace only the ones in the import file.
+2. Delete all existing cycle days and import cycle days from file.`,
+    replaceOption: 'Import and replace',
+    deleteOption: 'Import and delete existing',
+    errors: {
+      couldNotOpenFile: 'Could not open file',
+      postFix: 'No data was imported or changed'
+    },
+    success: {
+      message: 'Data successfully imported'
+    }
+  }
 }
\ No newline at end of file
diff --git a/components/settings.js b/components/settings.js
index 3abc167c6701c1c7db6ce8d1a252d023f0343961..97907b101cd7e527d4f351d5025fd93fe39adb42 100644
--- a/components/settings.js
+++ b/components/settings.js
@@ -7,9 +7,12 @@ import {
 } from 'react-native'
 
 import Share from 'react-native-share'
-import getDataAsCsvDataUri from '../lib/export-to-csv'
+import { DocumentPicker, DocumentPickerUtil } from 'react-native-document-picker'
+import rnfs from 'react-native-fs'
 import styles from '../styles/index'
 import { settings as labels } from './labels'
+import getDataAsCsvDataUri from '../lib/import-export/export-to-csv'
+import importCsv from '../lib/import-export/import-from-csv'
 
 export default class Settings extends Component {
   render() {
@@ -18,36 +21,100 @@ export default class Settings extends Component {
         <View style={styles.homeButtons}>
           <View style={styles.homeButton}>
             <Button
-              onPress={async () => {
-                let data
-                try {
-                  data = getDataAsCsvDataUri()
-                  if (!data) {
-                    return Alert.alert(labels.errors.noData)
-                  }
-                } catch (err) {
-                  console.error(err)
-                  return Alert.alert(labels.errors.couldNotConvert)
-                }
-
-                try {
-                  await Share.open({
-                    title: labels.exportTitle,
-                    url: data,
-                    subject: labels.exportSubject,
-                    type: 'text/csv',
-                    showAppsToView: true
-                  })
-                } catch (err) {
-                  console.error(err)
-                  return Alert.alert(labels.errors.problemSharing)
-                }
-              }}
-              title={labels.buttonLabel}>
+              onPress={ openShareDialogAndExport }
+              title={labels.export.button}>
+            </Button>
+          </View>
+          <View style={styles.homeButton}>
+            <Button
+              title={labels.import.button}
+              onPress={ openImportDialogAndImport }>
             </Button>
           </View>
         </View>
       </ScrollView>
     )
   }
+}
+
+async function openShareDialogAndExport() {
+  let data
+  try {
+    data = getDataAsCsvDataUri()
+    if (!data) {
+      return alertError(labels.errors.noData)
+    }
+  } catch (err) {
+    console.error(err)
+    return alertError(labels.errors.couldNotConvert)
+  }
+
+  try {
+    await Share.open({
+      title: labels.export.title,
+      url: data,
+      subject: labels.export.subject,
+      type: 'text/csv',
+      showAppsToView: true
+    })
+  } catch (err) {
+    console.error(err)
+    return alertError(labels.export.errors.problemSharing)
+  }
+}
+
+function openImportDialogAndImport() {
+  Alert.alert(
+    labels.import.title,
+    labels.import.message,
+    [{
+      text: labels.import.replaceOption,
+      onPress: () => getFileContentAndImport({ deleteExisting: false })
+    }, {
+      text: labels.import.deleteOption,
+      onPress: () => getFileContentAndImport({ deleteExisting: true })
+    }, {
+      text: labels.shared.cancel, style: 'cancel', onPress: () => { }
+    }]
+  )
+}
+
+async function getFileContentAndImport({ deleteExisting }) {
+  let fileInfo
+  try {
+    fileInfo = await new Promise((resolve, reject) => {
+      DocumentPicker.show({
+        filetype: [DocumentPickerUtil.allFiles()],
+      }, (err, res) => {
+        if (err) return reject(err)
+        resolve(res)
+      })
+    })
+  } catch (err) {
+    // because cancelling also triggers an error, we do nothing here
+    return
+  }
+
+  let fileContent
+  try {
+    fileContent = await rnfs.readFile(fileInfo.uri, 'utf8')
+  } catch (err) {
+    return importError(labels.import.errors.couldNotOpenFile)
+  }
+
+  try {
+    await importCsv(fileContent, deleteExisting)
+    Alert.alert(labels.import.success.title, labels.import.success.message)
+  } catch(err) {
+    importError(err.message)
+  }
+}
+
+function alertError(msg) {
+  Alert.alert(labels.shared.errorTitle, msg)
+}
+
+function importError(msg) {
+  const postFixed = `${msg}\n\n${labels.import.errors.postFix}`
+  alertError(postFixed)
 }
\ No newline at end of file
diff --git a/db/index.js b/db/index.js
index 55b34b4710fdc7a80cf73ef7b8d22fb9e6ee5ecf..42fd320e8e30c324b841278c7786ea88b5610572 100644
--- a/db/index.js
+++ b/db/index.js
@@ -60,6 +60,22 @@ const DesireSchema = {
   }
 }
 
+const SexSchema = {
+  name: 'Sex',
+  properties: {
+    solo: { type: 'bool', optional: true },
+    partner: { type: 'bool', optional: true },
+    condom: { type: 'bool', optional: true },
+    pill: { type: 'bool', optional: true },
+    iud: { type: 'bool', optional: true },
+    patch: { type: 'bool', optional: true },
+    ring: { type: 'bool', optional: true },
+    implant: { type: 'bool', optional: true },
+    other: { type: 'bool', optional: true },
+    note: { type: 'string', optional: true }
+  }
+}
+
 const CycleDaySchema = {
   name: 'CycleDay',
   primaryKey: 'date',
@@ -88,6 +104,10 @@ const CycleDaySchema = {
     desire: {
       type: 'Desire',
       optional: true
+    },
+    sex: {
+      type: 'Sex',
+      optional: true
     }
   }
 }
@@ -100,7 +120,8 @@ const realmConfig = {
     MucusSchema,
     CervixSchema,
     NoteSchema,
-    DesireSchema
+    DesireSchema,
+    SexSchema
   ],
   // we only want this in dev mode
   deleteRealmIfMigrationNeeded: true
@@ -175,21 +196,17 @@ function getPreviousTemperature(cycleDay) {
   return winner.temperature.value
 }
 
-function getColumnNamesForCsv() {
-  return getPrefixedKeys('CycleDay')
-
-  function getPrefixedKeys(schemaName, prefix) {
-    const schema = db.schema.find(x => x.name === schemaName).properties
-    return Object.keys(schema).reduce((acc, key) => {
-      const prefixedKey = prefix ? [prefix, key].join('.') : key
-      const childSchemaName = schema[key].objectType
-      if (!childSchemaName) {
-        acc.push(prefixedKey)
-        return acc
-      }
-      acc.push(...getPrefixedKeys(childSchemaName, prefixedKey))
-      return acc
-    }, [])
+const schema = db.schema.reduce((acc, curr) => {
+  acc[curr.name] = curr.properties
+  return acc
+}, {})
+
+function tryToCreateCycleDay(day, i) {
+  try {
+    db.create('CycleDay', day)
+  } catch (err) {
+    const msg = `Line ${i + 1}(${day.date}): ${err.message}`
+    throw new Error(msg)
   }
 }
 
@@ -202,6 +219,23 @@ function getAmountOfCycleDays() {
   return earliestAsLocalDate.until(today, ChronoUnit.DAYS)
 }
 
+function tryToImportWithDelete(cycleDays) {
+  db.write(() => {
+    db.delete(db.objects('CycleDay'))
+    cycleDays.forEach(tryToCreateCycleDay)
+  })
+}
+
+function tryToImportWithoutDelete(cycleDays) {
+  db.write(() => {
+    cycleDays.forEach((day, i) => {
+      const existing = getCycleDay(day.date)
+      if (existing) db.delete(existing)
+      tryToCreateCycleDay(day, i)
+    })
+  })
+}
+
 export {
   saveSymptom,
   getOrCreateCycleDay,
@@ -212,6 +246,8 @@ export {
   deleteAll,
   getPreviousTemperature,
   getCycleDay,
-  getColumnNamesForCsv,
-  getAmountOfCycleDays
+  getAmountOfCycleDays,
+  schema,
+  tryToImportWithDelete,
+  tryToImportWithoutDelete
 }
diff --git a/ios/drip.xcodeproj/project.pbxproj b/ios/drip.xcodeproj/project.pbxproj
index b6ef381adb071d4eeaa197654f688d901e5f4343..25f1f7601b795048c76bb96a0d0b2d95dddf0838 100644
--- a/ios/drip.xcodeproj/project.pbxproj
+++ b/ios/drip.xcodeproj/project.pbxproj
@@ -56,6 +56,8 @@
 		DB91E6CCC3EB4A549D947797 /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 4902D5DCD46748BD8DC403FD /* Octicons.ttf */; };
 		3DF2498A20844F298CD84CC3 /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E954835D62BD45F0A5FFC523 /* SimpleLineIcons.ttf */; };
 		A1410AC4C98A49B2820D9E45 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B6F5078F7DEC470782757471 /* Zocial.ttf */; };
+		29DF0CCC1AEA4C92BCA0BCCD /* libRNDocumentPicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D211D71BE5A8436A978770A9 /* libRNDocumentPicker.a */; };
+		17AD822C42A44BADA96BD860 /* libRNFS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 84CCEBD3B2C44758853BC941 /* libRNFS.a */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -383,6 +385,10 @@
 		4902D5DCD46748BD8DC403FD /* Octicons.ttf */ = {isa = PBXFileReference; name = "Octicons.ttf"; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
 		E954835D62BD45F0A5FFC523 /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; name = "SimpleLineIcons.ttf"; path = "../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
 		B6F5078F7DEC470782757471 /* Zocial.ttf */ = {isa = PBXFileReference; name = "Zocial.ttf"; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
+		1F05FE29622E4F21AF70C2B7 /* RNDocumentPicker.xcodeproj */ = {isa = PBXFileReference; name = "RNDocumentPicker.xcodeproj"; path = "../node_modules/react-native-document-picker/ios/RNDocumentPicker.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
+		D211D71BE5A8436A978770A9 /* libRNDocumentPicker.a */ = {isa = PBXFileReference; name = "libRNDocumentPicker.a"; path = "libRNDocumentPicker.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
+		49089E09BFCF4F3DB209B6E9 /* RNFS.xcodeproj */ = {isa = PBXFileReference; name = "RNFS.xcodeproj"; path = "../node_modules/react-native-fs/RNFS.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
+		84CCEBD3B2C44758853BC941 /* libRNFS.a */ = {isa = PBXFileReference; name = "libRNFS.a"; path = "libRNFS.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -416,6 +422,8 @@
 				D91133DCE120440893E2FD2E /* libz.tbd in Frameworks */,
 				26DC04B498C64CE5AAA0C4F8 /* libRNShare.a in Frameworks */,
 				AED64B7892744F21B3A156BB /* libRNVectorIcons.a in Frameworks */,
+				29DF0CCC1AEA4C92BCA0BCCD /* libRNDocumentPicker.a in Frameworks */,
+				17AD822C42A44BADA96BD860 /* libRNFS.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -608,6 +616,8 @@
 				7F6C9FA9B66B453CA602B334 /* RealmReact.xcodeproj */,
 				4E6AB77B55F2491487B6124E /* RNShare.xcodeproj */,
 				D1E5ACC4B66345868F556374 /* RNVectorIcons.xcodeproj */,
+				1F05FE29622E4F21AF70C2B7 /* RNDocumentPicker.xcodeproj */,
+				49089E09BFCF4F3DB209B6E9 /* RNFS.xcodeproj */,
 			);
 			name = Libraries;
 			sourceTree = "<group>";
@@ -1272,12 +1282,16 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SRCROOT)/../node_modules/realm/src/**",
 					"$(SRCROOT)/../node_modules/react-native-share/ios",
 					"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
+					"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
+					"$(SRCROOT)/../node_modules/react-native-fs/**",
 				);
 			};
 			name = Debug;
@@ -1299,12 +1313,16 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SRCROOT)/../node_modules/realm/src/**",
 					"$(SRCROOT)/../node_modules/react-native-share/ios",
 					"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
+					"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
+					"$(SRCROOT)/../node_modules/react-native-fs/**",
 				);
 			};
 			name = Release;
@@ -1329,6 +1347,8 @@
 					"$(SRCROOT)/../node_modules/realm/src/**",
 					"$(SRCROOT)/../node_modules/react-native-share/ios",
 					"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
+					"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
+					"$(SRCROOT)/../node_modules/react-native-fs/**",
 				);
 			};
 			name = Debug;
@@ -1352,6 +1372,8 @@
 					"$(SRCROOT)/../node_modules/realm/src/**",
 					"$(SRCROOT)/../node_modules/react-native-share/ios",
 					"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
+					"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
+					"$(SRCROOT)/../node_modules/react-native-fs/**",
 				);
 			};
 			name = Release;
@@ -1382,12 +1404,16 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SRCROOT)/../node_modules/realm/src/**",
 					"$(SRCROOT)/../node_modules/react-native-share/ios",
 					"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
+					"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
+					"$(SRCROOT)/../node_modules/react-native-fs/**",
 				);
 			};
 			name = Debug;
@@ -1418,12 +1444,16 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SRCROOT)/../node_modules/realm/src/**",
 					"$(SRCROOT)/../node_modules/react-native-share/ios",
 					"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
+					"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
+					"$(SRCROOT)/../node_modules/react-native-fs/**",
 				);
 			};
 			name = Release;
@@ -1453,12 +1483,16 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SRCROOT)/../node_modules/realm/src/**",
 					"$(SRCROOT)/../node_modules/react-native-share/ios",
 					"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
+					"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
+					"$(SRCROOT)/../node_modules/react-native-fs/**",
 				);
 			};
 			name = Debug;
@@ -1488,12 +1522,16 @@
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
+					"\"$(SRCROOT)/$(TARGET_NAME)\"",
 				);
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SRCROOT)/../node_modules/realm/src/**",
 					"$(SRCROOT)/../node_modules/react-native-share/ios",
 					"$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager",
+					"$(SRCROOT)/../node_modules/react-native-document-picker/ios/RNDocumentPicker",
+					"$(SRCROOT)/../node_modules/react-native-fs/**",
 				);
 			};
 			name = Release;
diff --git a/lib/export-to-csv.js b/lib/import-export/export-to-csv.js
similarity index 91%
rename from lib/export-to-csv.js
rename to lib/import-export/export-to-csv.js
index d3b1321662431f90a7ead8a2f87ac6bf038b161f..c5bca2b3ffb4c4afd5669fa3d62c93e4ac1468ca 100644
--- a/lib/export-to-csv.js
+++ b/lib/import-export/export-to-csv.js
@@ -1,7 +1,7 @@
 import objectPath from 'object-path'
 import { Base64 } from 'js-base64'
-
-import { getColumnNamesForCsv, cycleDaysSortedByDate } from '../db'
+import { cycleDaysSortedByDate } from '../../db'
+import getColumnNamesForCsv from './get-csv-column-names'
 
 export default function makeDataURI() {
   if (!cycleDaysSortedByDate.length) return null
diff --git a/lib/import-export/get-csv-column-names.js b/lib/import-export/get-csv-column-names.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b63943ab6b5a6b05eee6460684b62b3947f3075
--- /dev/null
+++ b/lib/import-export/get-csv-column-names.js
@@ -0,0 +1,19 @@
+import { schema } from '../../db'
+
+export default function getColumnNamesForCsv() {
+  return getPrefixedKeys('CycleDay')
+
+  function getPrefixedKeys(schemaName, prefix) {
+    const model = schema[schemaName]
+    return Object.keys(model).reduce((acc, key) => {
+      const prefixedKey = prefix ? [prefix, key].join('.') : key
+      const childSchemaName = model[key].objectType
+      if (!childSchemaName) {
+        acc.push(prefixedKey)
+        return acc
+      }
+      acc.push(...getPrefixedKeys(childSchemaName, prefixedKey))
+      return acc
+    }, [])
+  }
+}
\ No newline at end of file
diff --git a/lib/import-export/import-from-csv.js b/lib/import-export/import-from-csv.js
new file mode 100644
index 0000000000000000000000000000000000000000..77c2444430072f4441340dcef4e732ebcf2fbf9a
--- /dev/null
+++ b/lib/import-export/import-from-csv.js
@@ -0,0 +1,82 @@
+import csvParser from 'csvtojson'
+import isObject from 'isobject'
+import { schema, tryToImportWithDelete, tryToImportWithoutDelete } from '../../db'
+import getColumnNamesForCsv from './get-csv-column-names'
+
+export default async function importCsv(csv, deleteFirst) {
+  const parseFuncs = {
+    bool: val => {
+      if (val.toLowerCase() === 'true') return true
+      if (val.toLowerCase() === 'false') return false
+      return val
+    },
+    int: parseNumberIfPossible,
+    float: parseNumberIfPossible,
+    double: parseNumberIfPossible,
+    string: val => val
+  }
+
+  function parseNumberIfPossible(val) {
+    // Number and parseFloat catch different cases of weirdness,
+    // so we test them both
+    if (isNaN(Number(val)) || isNaN(parseFloat(val))) return val
+    return Number(val)
+  }
+
+  const config = {
+    ignoreEmpty: true,
+    colParser: getColumnNamesForCsv().reduce((acc, colName) => {
+      const path = colName.split('.')
+      const dbType = getDbType(schema.CycleDay, path)
+      acc[colName] = item => {
+        if (item === '') return null
+        return parseFuncs[dbType](item)
+      }
+      return acc
+    }, {})
+  }
+
+  const cycleDays = await csvParser(config)
+    .fromString(csv)
+    .on('header', validateHeaders)
+
+  //remove symptoms where all fields are null
+  putNullForEmptySymptoms(cycleDays)
+
+  if (deleteFirst) {
+    tryToImportWithDelete(cycleDays)
+  } else {
+    tryToImportWithoutDelete(cycleDays)
+  }
+}
+
+function validateHeaders(headers) {
+  const expectedHeaders = getColumnNamesForCsv()
+  if (!headers.every(header => {
+    return expectedHeaders.indexOf(header) > -1
+  })) {
+    const msg = `Expected CSV column titles to be ${expectedHeaders.join()}`
+    throw new Error(msg)
+  }
+}
+
+function putNullForEmptySymptoms(data) {
+  data.forEach(replaceWithNullIfAllPropertiesAreNull)
+
+  function replaceWithNullIfAllPropertiesAreNull(obj) {
+    Object.keys(obj).forEach((key) => {
+      if (!isObject(obj[key])) return
+      if (Object.values(obj[key]).every(val => val === null)) {
+        obj[key] = null
+        return
+      }
+      replaceWithNullIfAllPropertiesAreNull(obj[key])
+    })
+  }
+}
+
+function getDbType(modelProperties, path) {
+  if (path.length === 1) return modelProperties[path[0]].type
+  const modelName = modelProperties[path[0]].objectType
+  return getDbType(schema[modelName], path.slice(1))
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 86dcf0073f06b33f99e247ebd19f22b8e339005e..9823a713e6ae35c8dbfa4b2a799e41bcfce4de33 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2015,6 +2015,11 @@
         }
       }
     },
+    "base-64": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
+      "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs="
+    },
     "base64-js": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
@@ -2066,6 +2071,11 @@
         "inherits": "~2.0.0"
       }
     },
+    "bluebird": {
+      "version": "3.5.1",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
+      "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
+    },
     "boom": {
       "version": "2.10.1",
       "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
@@ -2545,6 +2555,26 @@
         "boom": "2.x.x"
       }
     },
+    "csvtojson": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/csvtojson/-/csvtojson-2.0.8.tgz",
+      "integrity": "sha512-DC6YFtsJiA7t/Yz+KjzT6GXuKtU/5gRbbl7HJqvDVVir+dxdw2/1EgwfgJdnsvUT7lOnON5DvGftKuYWX1nMOQ==",
+      "requires": {
+        "bluebird": "^3.5.1",
+        "lodash": "^4.17.3",
+        "strip-bom": "^2.0.0"
+      },
+      "dependencies": {
+        "strip-bom": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+          "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+          "requires": {
+            "is-utf8": "^0.2.0"
+          }
+        }
+      }
+    },
     "dashdash": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -3341,6 +3371,16 @@
         "randomatic": "^3.0.0",
         "repeat-element": "^1.1.2",
         "repeat-string": "^1.5.2"
+      },
+      "dependencies": {
+        "isobject": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+          "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+          "requires": {
+            "isarray": "1.0.0"
+          }
+        }
       }
     },
     "finalhandler": {
@@ -4657,6 +4697,11 @@
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
       "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
     },
+    "is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
+    },
     "is-windows": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -4673,12 +4718,9 @@
       "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
     },
     "isobject": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
-      "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
-      "requires": {
-        "isarray": "1.0.0"
-      }
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
     },
     "isomorphic-fetch": {
       "version": "2.2.1",
@@ -6351,6 +6393,11 @@
       "resolved": "https://registry.npmjs.org/react-native-dismiss-keyboard/-/react-native-dismiss-keyboard-1.0.0.tgz",
       "integrity": "sha1-MohiQrPyMX4SHzrrmwpYXiuHm0k="
     },
+    "react-native-document-picker": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/react-native-document-picker/-/react-native-document-picker-2.1.0.tgz",
+      "integrity": "sha512-BFCBXwz8xuLvHLVFVeQM+RhaY8yZ38PEWt9WSbq5VIoZ/VssP6uu51XxOfdwaMALOrAHIojK0SiYnd155upZAg=="
+    },
     "react-native-drawer-layout": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/react-native-drawer-layout/-/react-native-drawer-layout-1.3.2.tgz",
@@ -6367,6 +6414,15 @@
         "react-native-drawer-layout": "1.3.2"
       }
     },
+    "react-native-fs": {
+      "version": "2.10.14",
+      "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.10.14.tgz",
+      "integrity": "sha512-4bCzkg4dE/xUyXkMVz0AiyqLKAgTZPlZl/nEzRiSr2q6VnWDgO229MSgHLHhUtD2cqZkV0Z83WEbGpvXxWOAHA==",
+      "requires": {
+        "base-64": "^0.1.0",
+        "utf8": "^2.1.1"
+      }
+    },
     "react-native-modal": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-3.1.0.tgz",
@@ -8323,6 +8379,11 @@
       "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
       "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
     },
+    "utf8": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz",
+      "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY="
+    },
     "util": {
       "version": "0.10.3",
       "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
diff --git a/package.json b/package.json
index 58f26381f17f6a93962d6b0ef88a1ae8fd9050e0..4a07999ff691225c6f4e3a13a3519d973a56e896 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,9 @@
   },
   "dependencies": {
     "assert": "^1.4.1",
+    "csvtojson": "^2.0.8",
     "date-range": "0.0.2",
+    "isobject": "^3.0.1",
     "js-base64": "^2.4.8",
     "js-joda": "^1.8.2",
     "moment": "^2.22.1",
@@ -24,6 +26,8 @@
     "react": "16.4.1",
     "react-native": "^0.56.0",
     "react-native-calendars": "^1.19.3",
+    "react-native-document-picker": "^2.1.0",
+    "react-native-fs": "^2.10.14",
     "react-native-modal-datetime-picker-nevo": "^4.11.0",
     "react-native-share": "^1.1.0",
     "react-native-simple-radio-button": "^2.7.1",