How to Make Phone Calls With SwiftUI

In this tutorial, you will create a SwiftUI application that can make calls to a specified phone number using an AWS Lambda function and the Vonage Client SDK for iOS.


  • Cocoapods to install the Vonage Client SDK for iOS.
  • ngrok for exposing your local machine to the internet.
  • Our Command Line Interface. It can be installed with npm install nexmo-cli@beta -g.##

Vonage API Account


In this case, we will be using the Conversation API so the Vonage application you will create requires two URLs to be set up: an answer_url and an event_url.

The answer_url needs to return a Call Control Object (NCCO) which will tell Vonage how to handle the call. The AWS Lambda function will return an NCCO based on the number that is specified in the iOS application.

Creating the Lambda Function

In your terminal enter git clone This will clone the project to your machine. Open the project in Xcode then build and run (CMD + R). This will run the Lambda function locally on port 7000. Now you can use ngrok to expose it to the internet.

To do so run ngrok http 7000 in your terminal. The forwarding URL that ngrok provides is what is needed for the answer_url of the Vonage application.

Scaffolding the Application

Create an Application

This will save your application’s private key to the private.key file and output your application's ID, you will need them for the next step.

Create a User

This will add a user, with the username Alice, to your application and output their unique ID.

Create a JWT

We will be using the private key, application ID and username from the earlier sections to create the JWT needed for your iOS application. Again, this is done via the CLI. Replace APPLICATION_ID with the application ID from the earlier step.

This will output the JWT for the user Alice that has been signed using your private key. Keep hold of this as you will need it later.

Creating the iOS Application

Create an Xcode Project

Install Client SDK

  1. Run the pod init command to create a new Podfile for your project.
  2. Open the Podfile in Xcode using open -a Xcode Podfile.
  3. Update the Podfile to have NexmoClient as a dependency.
  1. Install the SDK using pod install.
  2. Open the new xcworkspace file in Xcode using open SwiftUICall.xcworkspace.

Microphone Permissions

The first step is to edit the Info.plist file. This is a file that contains all the metadata required for the application. Add a new entry to the file by hovering your mouse over the last entry in the list and click the little + button that appears. From the dropdown list, pick Privacy - Microphone Usage Description and add Microphone access required to make and receive audio calls. for its value.

You will do the second step for requesting microphone permissions later on in the tutorial.

Creating the Model Class

Then at the bottom of the file create a new class called CallModel.

Within this class, define the properties needed.

The @Published property wrapper is how the UI will know when to react to changes from the model class, this is all handled for you as the class conforms to the ObservedObject protocol. The call property is used to store the call object and audioSession is used to request the microphone permissions. To complete requesting microphone permissions for the app add the following function to the CallModel class.

This will first check if the permissions have already been granted, if not it will request them and print out the outcome to the console. Next, you need to log in as the Alice user with the Client SDK. To do so add the next function to the CallModel class, replacing ALICE_JWT with the JWT from earlier.

This function checks if the client is already logged in, if it isn’t it will use the JWT you generated earlier to log in and set the delegate for the client to this class. The NXMClientDelegate is how the Client SDK communicates changes with the Vonage servers back to your application. Next, implement the required delegate functions.

When there is an error or change in status, the status property is updated. The next two functions you need to add will allow for your application to make and end calls. Add the following functions:

The callNumber function uses the Client SDK to make a call to the number from the number property. The callHandler parameter is set to server, this uses the answer_url from earlier on in the tutorial.

Vonage will then make a HTTP call to your answer_url with the number from the iOS application, then the Lambda function will return an NCCO with instructions for Vonage to connect your app to the number.

If this all succeeds the Client SDK returns a call object which is stored on the class. The endCall function hangs up the call, sets the call property to nil and sets the published isCalling boolean back to false so the UI can update.

The final function that you need to add to the CallModel calls both requestPermissionsIfNeeded and loginIfNeeded functions.

Create the User Interface

When the view appears, it will call the setup function on the model class, this will request the microphone permissions and log the client in. Doing so will update the status property on the model class and the change in its value will prompt the ContentView to update!

Now that the client is logged in, you can now use the rest of the published properties on the model class to build the rest of the UI. Add the following block of code to the VStack.

If the client is connected, the TextField will animate onto the view. The value of the TextField is bound to the number property of the model class, this is done by using the $ sign. Once a valid length of number has been entered the conditions for showing the call button will be met, and once a call has started the conditions will no longer be met but the conditions for the end call button will be. So only one button shows at a time, and all the updating of the UI will be handled for you!

Run Your Application

You can find the completed project on GitHub. You can do a lot more with the Client SDK, learn more on

Developer content from the team at Vonage, including posts on our Java, Node.js, Python, DotNet, Ruby and Go SDKs