{"id":28622952,"url":"https://github.com/verygoodsecurity/vgs-collect-ios","last_synced_at":"2025-10-09T06:55:26.800Z","repository":{"id":37735861,"uuid":"202370571","full_name":"verygoodsecurity/vgs-collect-ios","owner":"verygoodsecurity","description":"VGS Collect iOS SDK ","archived":false,"fork":false,"pushed_at":"2025-09-15T10:14:49.000Z","size":67060,"stargazers_count":23,"open_issues_count":7,"forks_count":17,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-09-15T12:14:10.557Z","etag":null,"topics":["collect","credit-card","ios","pci","pci-dss","security","ssn","swift","team-developer-experience","tokenization","vgs","zerodata"],"latest_commit_sha":null,"homepage":"https://www.verygoodsecurity.com/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/verygoodsecurity.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-08-14T14:47:16.000Z","updated_at":"2025-07-25T14:20:15.000Z","dependencies_parsed_at":"2023-12-18T17:30:21.668Z","dependency_job_id":"49326f86-2536-4e73-8283-d8106a6c27ee","html_url":"https://github.com/verygoodsecurity/vgs-collect-ios","commit_stats":{"total_commits":490,"total_committers":13,"mean_commits":37.69230769230769,"dds":0.7306122448979592,"last_synced_commit":"a05fa24a4fd8d6b3d69bb99b59730c32a560ce5f"},"previous_names":[],"tags_count":86,"template":false,"template_full_name":null,"purl":"pkg:github/verygoodsecurity/vgs-collect-ios","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/verygoodsecurity%2Fvgs-collect-ios","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/verygoodsecurity%2Fvgs-collect-ios/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/verygoodsecurity%2Fvgs-collect-ios/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/verygoodsecurity%2Fvgs-collect-ios/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/verygoodsecurity","download_url":"https://codeload.github.com/verygoodsecurity/vgs-collect-ios/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/verygoodsecurity%2Fvgs-collect-ios/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000864,"owners_count":26082951,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["collect","credit-card","ios","pci","pci-dss","security","ssn","swift","team-developer-experience","tokenization","vgs","zerodata"],"created_at":"2025-06-12T06:13:53.244Z","updated_at":"2025-10-09T06:55:26.794Z","avatar_url":"https://github.com/verygoodsecurity.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CircleCI](https://dl.circleci.com/status-badge/img/gh/verygoodsecurity/vgs-collect-ios/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/verygoodsecurity/vgs-collect-ios/tree/master)\n[![license](https://img.shields.io/github/license/verygoodsecurity/vgs-collect-ios.svg)]()\n[![Platform](https://img.shields.io/cocoapods/p/VGSCollectSDK.svg?style=flat)](https://github.com/verygoodsecurity/vgs-collect-ios)\n[![swift](https://img.shields.io/badge/swift-5-orange)]()\n[![swiftui](https://img.shields.io/badge/SwiftUI-524520?logo=swift)]()\n[![SwiftPM Compatible](https://img.shields.io/badge/SwiftPM-Compatible-brightgreen)]()\n[![Cocoapods Compatible](https://img.shields.io/cocoapods/v/VGSCollectSDK.svg?style=flat)](https://cocoapods.org/pods/VGSCollectSDK)\n\u003cimg src=\"./images/VGSZeroData.png\" height=\"20\"\u003e\n\n# VGS Collect iOS SDK\n\nVGS Collect - is a product suite that allows customers to collect information securely without possession of it. VGSCollect iOS SDK  allows you to securely collect data from your users via forms without having to have that data pass through your systems. The form fields behave like traditional input fields while securing access to the unsecured data.\n\nTable of contents\n=================\n\n\u003c!--ts--\u003e\n   * [Before you start](#before-you-start)\n   * [Integration](#integration)\n      * [Swift Package Manager](#swift-package-manager) \n      * [CocoaPods](#cocoapods)\n   * [Usage](#usage)\n      * [Create VGSCollect instance and VGS UI Elements](#create-vgscollect-instance-and-vgs-ui-elements)\n      * [Scan Credit Card Data](#scan-credit-card-data)\n      * [Upload Files](#upload-files)\n      * [SwiftUI support](#swiftui-support)\n      * [Demo Application](#demo-application)\n      * [Documentation](#documentation)\n      * [Releases](#releases)\n      * [Privacy](#privacy)\n   * [Dependencies](#dependencies)\n   * [License](#license)\n\u003c!--te--\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003cimg src=\"images/vgs-collect-ios-state.png\" width=\"200\" alt=\"VGS Collect iOS SDK State\" hspace=\"20\"\u003e\n\t\u003cimg src=\"images/vgs-collect-ios-response.png\" width=\"200\" alt=\"VGS Collect iOS SDK Response\" hspace=\"20\"\u003e\n\u003c/p\u003e\n\n\n## Before you start\nYou should have your organization registered at \u003ca href=\"https://dashboard.verygoodsecurity.com/dashboard/\"\u003eVGS Dashboard\u003c/a\u003e. Sandbox vault will be pre-created for you. You should use your `\u003cvaultId\u003e` to start collecting data. Follow integration guide below.\n\n# Integration\n\n### Swift Package Manager \n\nThe [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler.\nXcode with Swift tools version of 5.9+ is required for VGSCollectSDK.\nTo check your current Swift tools version run in your terminal:\n\n```ruby\nxcrun swift -version\n```\n\nTo use Swift Package Manager, in Xcode add the https://github.com/verygoodsecurity/vgs-collect-ios.git dependency and choose the `Exact` version.\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"images/VGSCollect_CardScan_SPM_1.png\" width=\"70%\"\u003e\n\u003c/p\u003e\n\nSelect `VGSCollectSDK` and optionally other packages provided with `VGSCollectSDK`:\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"images/VGSCollect_CardScan_SPM_2.png\" width=\"70%\"\u003e\n\u003c/p\u003e\n\n### CocoaPods\n\n[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit CocoaPods website. To integrate VGSCollectSDK into your Xcode project using CocoaPods, specify it in your `Podfile`:\n\n```ruby\npod 'VGSCollectSDK'\n```\n\n## Usage\n\n### Import SDK into your file\n```swift\n\nimport VGSCollectSDK\n\n```\n### Create VGSCollect instance and VGS UI Elements\nUse your `\u003cvaultId\u003e` to initialize VGSCollect instance. You can get it in your [organisation dashboard](https://dashboard.verygoodsecurity.com/).\n\n### Code example\n\n\u003ctable\u003e\n  \u003ctr\"\u003e\n    \u003cth \u003eHere's an example\u003c/th\u003e\n    \u003cth width=\"27%\"\u003eIn Action\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003eCustomize  VGSTextFields...\u003c/td\u003e\n     \u003cth rowspan=\"2\"\u003e\u003cimg src=\"images/add-card.gif\"\u003e\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n\n    /// Initialize VGSCollect instance\n    var vgsCollect = VGSCollect(id: \"vauiltId\", environment: .sandbox)\n\n    /// VGS UI Elements\n    var cardNumberField = VGSCardTextField()\n    var cardHolderNameField = VGSTextField()\n    var expCardDateField = VGSTextField()\n    var cvcField = VGSTextField()\n\n    /// Native UI Elements\n    @IBOutlet weak var stackView: UIStackView!\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        /// Create card number field configuration\n        let cardConfiguration = VGSConfiguration(collector: vgsCollect,\n\t                                         fieldName: \"card_number\")\n        cardConfiguration.type = .cardNumber\n        cardConfiguration.isRequiredValidOnly = true\n\n        /// Setup configuration to card number field\n        cardNumberField.configuration = cardConfiguration\n        cardNumberField.placeholder = \"Card Number\"\n        stackView.addArrangedSubview(cardNumberField)\n\n        /// Setup next textfields...\n    }\n    ...\n  \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e... observe filed states \u003c/td\u003e\n     \u003cth rowspan=\"2\"\u003e\u003cimg src=\"images/state.gif\"\u003e\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n\t\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        ...\n        \n        /// Setup delegate\n        cardNumberField.delegate = self\n    }\n    \n  extension ViewController: VGSTextFieldDelegate {\n    func vgsTextFieldDidChange(_ textField: VGSTextField) {\n      textField.borderColor = textField.state.isValid  ? .gray : .red\n\n      /// Check Card Number Field State with addition attributes\n      if let cardState = textField.state as? VGSCardState, cardState.isValid {\n          print(\"THIS IS: \\(cardState.cardBrand.stringValue) - \\(cardState.bin.prefix(4)) **** **** \\(cardState.last4)\")\n      }\n    }\n  }\n  \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\"\u003e... send data to your Vault\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\"\u003e\n        \n    // ...\n\n    // MARK: - Send data    \n    func sendData() {\n    \n        /// handle fields validation before send data\n        guard cardNumberField.state.isValid else {\n\t\tprint(\"cardNumberField input is not valid\")\n        }\n\t\n        /// extra information will be sent together with all sensitive card information\n        var extraData = [String: Any]()\n        extraData[\"customKey\"] = \"Custom Value\"\n\n        /// send data to your Vault\n        vgsCollect.sendData(path: \"/post\", extraData: extraData) { [weak self](response) in\n          switch response {\n            case .success(let code, let data, let response):\n              // parse data\n            case .failure(let code, let data, let response, let error):\n              // handle failed request\n              switch code {\n                // handle error codes\n              }\n          }\n        }\n    }\n  \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n**VGSCardTextField** automatically detects card provider and display card brand icon in the input field.\n\n\n### Scan Credit Card Data\nVGS Collect SDK provides optional card scan solution. It's required to use only Scan modules provided by VGS, which are audited by VGS PCI requirements.\n\n#### Integrate with Cocoapods\n\nAdd 'VGSCollectSDK' alongside with one of scan modules pod:\n\n```ruby\npod 'VGSCollectSDK'\n\n# Add one of available scan providers\npod 'VGSCollectSDK/BlinkCard'  \n```\n#### Integrate with Swift Package Manager\n\nTo use **BlinkCard** add `VGSCollectSDK`, `VGSBlinkCardCollector` packages to your target. \n\n#### Code Example\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eHere's an example\u003c/th\u003e\n    \u003cth width=\"25%\"\u003eIn Action\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003eSetup  VGSBlinkCardController...\u003c/td\u003e\n    \u003cth rowspan=\"2\"\u003e\u003cimg src=\"images/card-scan.gif\"\u003e\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n    \n    class ViewController: UIViewController {\n        /// Init VGSBlinkCardController\n        var scanController: VGSBlinkCardController?\n\n        /// Init VGSTextFields...\n\n        override func viewDidLoad() {\n          super.viewDidLoad()\n\n          // Init VGSBlinkCardController with BlinkCard license key and delegate\n            scanController = VGSBlinkCardController(licenseKey: \"\u003cblinkCardLicenseKey\u003e\", delegate: self, onError: { errorCode in\n              print(\"BlinkCard license error, code: \\(errorCode)\")\n            })\n        }\n\n        /// Present scan controller \n        func scanData() {\n          scanController?.presentCardScanner(on: self, animated: true, modalPresentationStyle: .fullScreen, completion: nil)\n        }\n    }\n    ...\n  \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\"\u003e... handle VGSBlinkCardControllerDelegate\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\"\u003e\n\t    \n    // ...\n    \n    /// Implement VGSBlinkCardControllerDelegate methods\n  extension ViewController: VGSBlinkCardControllerDelegate {\n    func textFieldForScannedData(type: VGSBlinkCardDataType) -\u003e VGSTextField? {\n      // match VGSTextField with scanned data\n      switch type {\n      case .expirationDate:\n          return expCardDate\n      case .cardNumber:\n          return cardNumber\n      case .cvc:\n        return cvcCardNum\n      case .name:\n        return cardHolderName\n      default:\n          return nil\n      }\n    }\n  \n    func userDidFinishScan() {\n      scanController?.dismissCardScanner(animated: true, completion: {\n          // add actions on scan controller dismiss completion\n      })\n    }\n  \n    func userDidCancelScan() {\n      scanController?.dismissCardScanner(animated: true, completion: {\n          // add actions on scan controller dismiss completion\n      })\n    }\n  }\n\n  \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nHandle `VGSBlinkCardControllerDelegate` functions. To setup scanned data into specific  VGSTextField implement `textFieldForScannedData:` . If scanned data is valid it will be set in your VGSTextField automatically after user confirmation. Check  `VGSBlinkCardDataType` to get available scand data types.\n\nDon't forget to add **NSCameraUsageDescription** key and description into your App ``Info.plist``.\n\n### Upload Files\n\nYou can add a file uploading functionality to your application with **VGSFilePickerController**.\n\n#### Code Example\n\n\u003ctable\u003e\n  \u003ctr\"\u003e\n    \u003cth  colspan=\"2\u003eHere's an example\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\"\u003eSetup  VGSFilePickerController...\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\"\u003e\n\t    \n    class FilePickerViewController: UIViewController, VGSFilePickerControllerDelegate {\n\n\t  var vgsCollect = VGSCollect(id: \"vailtId\", environment: .sandbox)\n\t  \n\t  /// Create strong referrence of VGSFilePickerController\n\t  var pickerController: VGSFilePickerController?\n\n\t  override func viewDidLoad() {\n\t      super.viewDidLoad()\n\n\t      /// create picker configuration\n\t      let filePickerConfig = VGSFilePickerConfiguration(collector: vgsCollect,\n\t      \t\t\t\t\t\t\tfieldName: \"secret_doc\",\n\t\t\t\t\t\t\t       fileSource: .photoLibrary)\n\n\t      /// init picket controller with configuration\n\t      pickerController = VGSFilePickerController(configuration: filePickerConfig)\n\n\t      /// handle picker delegates\n\t      pickerController?.delegate = self\n\t  }\n\n\t  /// Present picker controller\n\t  func presentFilePicker() {\n\t      pickerController?.presentFilePicker(on: self, animated: true, completion: nil)\n\t  }\n\t}\n\t...\n  \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e... handle VGSFilePickerControllerDelegate\u003c/td\u003e\n    \u003cth width=\"27%\"\u003eIn Action\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n\t\n\t// ...  \n\t\n\t// MARK: - VGSFilePickerControllerDelegate\n\t/// Check file info, selected by user\n\tfunc userDidPickFileWithInfo(_ info: VGSFileInfo) {\n\t\tlet fileInfo = \"\"\"\n\t\t\t    File info:\n\t\t\t    - fileExtension: \\(info.fileExtension ?? \"unknown\")\n\t\t\t    - size: \\(info.size)\n\t\t\t    - sizeUnits: \\(info.sizeUnits ?? \"unknown\")\n\t\t\t    \"\"\"\n\t\tprint(fileInfo)\n\t\tpickerController?.dismissFilePicker(animated: true,\n\t\t\t\t\t\t  completion: { [weak self] in\n\t\t\t\t\t\t  \n\t\t\tself?.sendFile()\n\t\t})\n\t}\n\n\t// Handle cancel file selection\n\tfunc userDidSCancelFilePicking() {\n\t\tpickerController?.dismissFilePicker(animated: true)\n\t}\n\n\t// Handle errors on picking the file\n\tfunc filePickingFailedWithError(_ error: VGSError) {\n\t\tpickerController?.dismissFilePicker(animated: true)\n\t}\n   \n  \u003c/td\u003e\n  \u003ctd\u003e\u003cimg src=\"images/file-picker.gif\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\"\u003e... send file to your Vault\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\"\u003e\n\t    \n\t// ...\n\n\t// MARK: - Send File\t\n\t/// Send file and extra data\n\tfunc sendFile() {\n\t\n\t\t/// add extra data to send request\t\n\t\tlet extraData = [\"document_holder\": \"Joe B\"]\n    \n      /// send file to your Vault\n      vgsCollect.sendFile(path: \"/post\", extraData: extraData) { [weak self](response) in\n        switch response {\n          case .success(let code, let data, let response):\n            /// remove file from VGSCollect storage\n            self?.vgsCollect.cleanFiles()\n          case .failure(let code, let data, let response, let error):\n            // handle failed request\n            switch code {\n              // handle error codes\n            }\n        }\n      }\n\t}\n  \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nUse vgsCollect.cleanFiles() to unassign file from associated VGSCollect instance whenever you need.\n\n### SwiftUI support\n\nVGS Collect iOS SDK provide support for integration with apps that are buid with SwiftUI toolkit by providing SwiftUI wrappers for all VGS textfields. Follow examples [here](./demoapp/demoapp/UseCases/SwiftUI/README.md).\n\n## Demo Application\nDemo application for collecting card data on iOS is \u003ca href=\"https://github.com/vgs-samples/very-spacy-food-iOS\"\u003ehere\u003c/a\u003e.\n\n\n### Documentation\n-  SDK Documentation: https://www.verygoodsecurity.com/docs/vgs-collect/ios-sdk\n-  API Documentation: https://verygoodsecurity.github.io/vgs-collect-ios/\n\n### Releases\nTo follow `VGSCollectSDK` updates and changes check the [releases](https://github.com/verygoodsecurity/vgs-collect-ios/releases) page.\n\n### Privacy\nVGSCollectSDK tracks a few key metrics to understand SDK features usage, which helps us know what areas need improvement. No personal information is tracked.\nYou can read more about VGS Privacy details ans iOS Privacy Manifest file at our [web site](https://www.verygoodsecurity.com/docs/vgs-collect/ios-sdk/privacy-details).\n\nYou can opt-out of metrics collection in `VGSAnalyticsClient`:\n```\nVGSAnalyticsClient.shared.shouldCollectAnalytics = false\n```\n\n## Dependencies\n- iOS 13+\n- Swift 5.9\n- Optional 3rd party libraries:\n  - [BlinkCard](https://github.com/blinkcard/blinkcard-ios)\n\n## License\n\n VGSCollect iOS SDK is released under the MIT license. [See LICENSE](https://github.com/verygoodsecurity/vgs-collect-ios/blob/master/LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverygoodsecurity%2Fvgs-collect-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fverygoodsecurity%2Fvgs-collect-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fverygoodsecurity%2Fvgs-collect-ios/lists"}